"Fossies" - the Fresh Open Source Software Archive

Member "tnftp-20200705/src/progressbar.c" (4 Jul 2020, 13307 Bytes) of package /linux/privat/tnftp-20200705.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "progressbar.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 20151004_vs_20200705.

    1 /*  $NetBSD: progressbar.c,v 1.16 2020/07/04 09:59:07 lukem Exp $   */
    2 /*  from    NetBSD: progressbar.c,v 1.23 2019/06/22 23:40:33 christos Exp   */
    3 
    4 /*-
    5  * Copyright (c) 1997-2009 The NetBSD Foundation, Inc.
    6  * All rights reserved.
    7  *
    8  * This code is derived from software contributed to The NetBSD Foundation
    9  * by Luke Mewburn.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   30  * POSSIBILITY OF SUCH DAMAGE.
   31  */
   32 
   33 #include "tnftp.h"
   34 
   35 #if 0   /* tnftp */
   36 
   37 #include <sys/cdefs.h>
   38 #ifndef lint
   39 __RCSID(" NetBSD: progressbar.c,v 1.23 2019/06/22 23:40:33 christos Exp  ");
   40 #endif /* not lint */
   41 
   42 /*
   43  * FTP User Program -- Misc support routines
   44  */
   45 #include <sys/param.h>
   46 #include <sys/types.h>
   47 #include <sys/time.h>
   48 
   49 #include <err.h>
   50 #include <errno.h>
   51 #include <signal.h>
   52 #include <stdio.h>
   53 #include <stdlib.h>
   54 #include <string.h>
   55 #include <time.h>
   56 #include <tzfile.h>
   57 #include <unistd.h>
   58 
   59 #endif  /* tnftp */
   60 
   61 #include "progressbar.h"
   62 
   63 #if !defined(NO_PROGRESS)
   64 /*
   65  * return non-zero if we're the current foreground process
   66  */
   67 int
   68 foregroundproc(void)
   69 {
   70     static pid_t pgrp = -1;
   71 
   72     if (pgrp == -1)
   73 #if GETPGRP_VOID
   74         pgrp = getpgrp();
   75 #else /* ! GETPGRP_VOID */
   76         pgrp = getpgrp(0);
   77 #endif /* ! GETPGRP_VOID */
   78 
   79     return (tcgetpgrp(fileno(ttyout)) == pgrp);
   80 }
   81 #endif  /* !defined(NO_PROGRESS) */
   82 
   83 
   84 static void updateprogressmeter(int);
   85 
   86 /*
   87  * SIGALRM handler to update the progress meter
   88  */
   89 static void
   90 updateprogressmeter(int dummy)
   91 {
   92     int oerrno = errno;
   93 
   94     progressmeter(0);
   95     errno = oerrno;
   96 }
   97 
   98 /*
   99  * List of order of magnitude suffixes, per IEC 60027-2.
  100  */
  101 #if !defined(NO_PROGRESS) || !defined(STANDALONE_PROGRESS)
  102 static const char * const suffixes[] = {
  103     "", /* 2^0  (byte) */
  104     "KiB",  /* 2^10 Kibibyte */
  105     "MiB",  /* 2^20 Mebibyte */
  106     "GiB",  /* 2^30 Gibibyte */
  107     "TiB",  /* 2^40 Tebibyte */
  108     "PiB",  /* 2^50 Pebibyte */
  109     "EiB",  /* 2^60 Exbibyte */
  110 #if 0
  111         /* The following are not necessary for signed 64-bit off_t */
  112     "ZiB",  /* 2^70 Zebibyte */
  113     "YiB",  /* 2^80 Yobibyte */
  114 #endif
  115 };
  116 #define NSUFFIXES   (int)(sizeof(suffixes) / sizeof(suffixes[0]))
  117 #endif
  118 
  119 /*
  120  * Display a transfer progress bar if progress is non-zero.
  121  * SIGALRM is hijacked for use by this function.
  122  * - Before the transfer, set filesize to size of file (or -1 if unknown),
  123  *   and call with flag = -1. This starts the once per second timer,
  124  *   and a call to updateprogressmeter() upon SIGALRM.
  125  * - During the transfer, updateprogressmeter will call progressmeter
  126  *   with flag = 0
  127  * - After the transfer, call with flag = 1
  128  */
  129 static struct timeval start;
  130 static struct timeval lastupdate;
  131 
  132 #define BUFLEFT (sizeof(buf) - len)
  133 
  134 void
  135 progressmeter(int flag)
  136 {
  137     static off_t lastsize;
  138     off_t cursize;
  139     struct timeval now, wait;
  140 #ifndef NO_PROGRESS
  141     struct timeval td;
  142     off_t abbrevsize, bytespersec;
  143     double elapsed;
  144     int ratio, i, remaining, barlength;
  145 
  146             /*
  147              * Work variables for progress bar.
  148              *
  149              * XXX: if the format of the progress bar changes
  150              *  (especially the number of characters in the
  151              *  `static' portion of it), be sure to update
  152              *  these appropriately.
  153              */
  154 #endif
  155 #if !defined(NO_PROGRESS) || !defined(STANDALONE_PROGRESS)
  156     size_t      len;
  157     char        buf[256];   /* workspace for progress bar */
  158 #endif
  159 #ifndef NO_PROGRESS
  160 #define BAROVERHEAD 45      /* non `*' portion of progress bar */
  161                     /*
  162                      * stars should contain at least
  163                      * sizeof(buf) - BAROVERHEAD entries
  164                      */
  165     static const char   stars[] =
  166 "*****************************************************************************"
  167 "*****************************************************************************"
  168 "*****************************************************************************";
  169 
  170 #endif
  171 
  172     if (flag == -1) {
  173         (void)gettimeofday(&start, NULL);
  174         lastupdate = start;
  175         lastsize = restart_point;
  176     }
  177 
  178     (void)gettimeofday(&now, NULL);
  179     cursize = bytes + restart_point;
  180     timersub(&now, &lastupdate, &wait);
  181     if (cursize > lastsize) {
  182         lastupdate = now;
  183         lastsize = cursize;
  184         wait.tv_sec = 0;
  185     } else {
  186 #ifndef STANDALONE_PROGRESS
  187         if (quit_time > 0 && wait.tv_sec > quit_time) {
  188             len = snprintf(buf, sizeof(buf), "\r\n%s: "
  189                 "transfer aborted because stalled for %lu sec.\r\n",
  190                 getprogname(), (unsigned long)wait.tv_sec);
  191             (void)write(fileno(ttyout), buf, len);
  192             alarmtimer(0);
  193             (void)xsignal(SIGALRM, SIG_DFL);
  194             siglongjmp(toplevel, 1);
  195         }
  196 #endif  /* !STANDALONE_PROGRESS */
  197     }
  198     /*
  199      * Always set the handler even if we are not the foreground process.
  200      */
  201 #ifdef STANDALONE_PROGRESS
  202     if (progress) {
  203 #else
  204     if (quit_time > 0 || progress) {
  205 #endif /* !STANDALONE_PROGRESS */
  206         if (flag == -1) {
  207             (void)xsignal_restart(SIGALRM, updateprogressmeter, 1);
  208             alarmtimer(1);      /* set alarm timer for 1 Hz */
  209         } else if (flag == 1) {
  210             alarmtimer(0);
  211             (void)xsignal(SIGALRM, SIG_DFL);
  212         }
  213     }
  214 #ifndef NO_PROGRESS
  215     if (!progress)
  216         return;
  217     len = 0;
  218 
  219     /*
  220      * print progress bar only if we are foreground process.
  221      */
  222     if (! foregroundproc())
  223         return;
  224 
  225     len += snprintf(buf + len, BUFLEFT, "\r");
  226     if (prefix)
  227       len += snprintf(buf + len, BUFLEFT, "%s", prefix);
  228     if (filesize > 0) {
  229         ratio = (int)((double)cursize * 100.0 / (double)filesize);
  230         ratio = MAX(ratio, 0);
  231         ratio = MIN(ratio, 100);
  232         len += snprintf(buf + len, BUFLEFT, "%3d%% ", ratio);
  233 
  234             /*
  235              * calculate the length of the `*' bar, ensuring that
  236              * the number of stars won't exceed the buffer size
  237              */
  238         barlength = MIN((int)(sizeof(buf) - 1), ttywidth) - BAROVERHEAD;
  239         if (prefix)
  240             barlength -= (int)strlen(prefix);
  241         if (barlength > 0) {
  242             i = barlength * ratio / 100;
  243             len += snprintf(buf + len, BUFLEFT,
  244                 "|%.*s%*s|", i, stars, (int)(barlength - i), "");
  245         }
  246     }
  247 
  248     abbrevsize = cursize;
  249     for (i = 0; abbrevsize >= 100000 && i < NSUFFIXES; i++)
  250         abbrevsize >>= 10;
  251     if (i == NSUFFIXES)
  252         i--;
  253     len += snprintf(buf + len, BUFLEFT, " " LLFP("5") " %-3s ",
  254         (LLT)abbrevsize,
  255         suffixes[i]);
  256 
  257     timersub(&now, &start, &td);
  258     elapsed = td.tv_sec + (td.tv_usec / 1000000.0);
  259 
  260     bytespersec = 0;
  261     if (bytes > 0) {
  262         bytespersec = bytes;
  263         if (elapsed > 0.0)
  264             bytespersec /= elapsed;
  265     }
  266     for (i = 1; bytespersec >= 1024000 && i < NSUFFIXES; i++)
  267         bytespersec >>= 10;
  268     len += snprintf(buf + len, BUFLEFT,
  269         " " LLFP("3") ".%02d %.2sB/s ",
  270         (LLT)(bytespersec / 1024),
  271         (int)((bytespersec % 1024) * 100 / 1024),
  272         suffixes[i]);
  273 
  274     if (filesize > 0) {
  275         if (bytes <= 0 || elapsed <= 0.0 || cursize > filesize) {
  276             len += snprintf(buf + len, BUFLEFT, "   --:-- ETA");
  277         } else if (wait.tv_sec >= STALLTIME) {
  278             len += snprintf(buf + len, BUFLEFT, " - stalled -");
  279         } else {
  280             remaining = (int)
  281                 ((filesize - restart_point) / (bytes / elapsed) -
  282                 elapsed);
  283             if (remaining >= 100 * SECSPERHOUR)
  284                 len += snprintf(buf + len, BUFLEFT,
  285                     "   --:-- ETA");
  286             else {
  287                 i = remaining / SECSPERHOUR;
  288                 if (i)
  289                     len += snprintf(buf + len, BUFLEFT,
  290                         "%2d:", i);
  291                 else
  292                     len += snprintf(buf + len, BUFLEFT,
  293                         "   ");
  294                 i = remaining % SECSPERHOUR;
  295                 len += snprintf(buf + len, BUFLEFT,
  296                     "%02d:%02d ETA", i / 60, i % 60);
  297             }
  298         }
  299     }
  300     if (flag == 1)
  301         len += snprintf(buf + len, BUFLEFT, "\n");
  302     (void)write(fileno(ttyout), buf, len);
  303 
  304 #endif  /* !NO_PROGRESS */
  305 }
  306 
  307 #ifndef STANDALONE_PROGRESS
  308 /*
  309  * Display transfer statistics.
  310  * Requires start to be initialised by progressmeter(-1),
  311  * direction to be defined by xfer routines, and filesize and bytes
  312  * to be updated by xfer routines
  313  * If siginfo is nonzero, an ETA is displayed, and the output goes to stderr
  314  * instead of ttyout.
  315  */
  316 void
  317 ptransfer(int siginfo)
  318 {
  319     struct timeval now, td, wait;
  320     double elapsed;
  321     off_t bytespersec;
  322     int remaining, hh, i;
  323     size_t len;
  324 
  325     char buf[256];      /* Work variable for transfer status. */
  326 
  327     if (!verbose && !progress && !siginfo)
  328         return;
  329 
  330     (void)gettimeofday(&now, NULL);
  331     timersub(&now, &start, &td);
  332     elapsed = td.tv_sec + (td.tv_usec / 1000000.0);
  333     bytespersec = 0;
  334     if (bytes > 0) {
  335         bytespersec = bytes;
  336         if (elapsed > 0.0)
  337             bytespersec /= elapsed;
  338     }
  339     len = 0;
  340     len += snprintf(buf + len, BUFLEFT, LLF " byte%s %s in ",
  341         (LLT)bytes, bytes == 1 ? "" : "s", direction);
  342     remaining = (int)elapsed;
  343     if (remaining > SECSPERDAY) {
  344         int days;
  345 
  346         days = remaining / SECSPERDAY;
  347         remaining %= SECSPERDAY;
  348         len += snprintf(buf + len, BUFLEFT,
  349             "%d day%s ", days, days == 1 ? "" : "s");
  350     }
  351     hh = remaining / SECSPERHOUR;
  352     remaining %= SECSPERHOUR;
  353     if (hh)
  354         len += snprintf(buf + len, BUFLEFT, "%2d:", hh);
  355     len += snprintf(buf + len, BUFLEFT,
  356         "%02d:%02d ", remaining / 60, remaining % 60);
  357 
  358     for (i = 1; bytespersec >= 1024000 && i < NSUFFIXES; i++)
  359         bytespersec >>= 10;
  360     if (i == NSUFFIXES)
  361         i--;
  362     len += snprintf(buf + len, BUFLEFT, "(" LLF ".%02d %.2sB/s)",
  363         (LLT)(bytespersec / 1024),
  364         (int)((bytespersec % 1024) * 100 / 1024),
  365         suffixes[i]);
  366 
  367     if (siginfo && bytes > 0 && elapsed > 0.0 && filesize >= 0
  368         && bytes + restart_point <= filesize) {
  369         remaining = (int)((filesize - restart_point) /
  370                   (bytes / elapsed) - elapsed);
  371         hh = remaining / SECSPERHOUR;
  372         remaining %= SECSPERHOUR;
  373         len += snprintf(buf + len, BUFLEFT, "  ETA: ");
  374         if (hh)
  375             len += snprintf(buf + len, BUFLEFT, "%2d:", hh);
  376         len += snprintf(buf + len, BUFLEFT, "%02d:%02d",
  377             remaining / 60, remaining % 60);
  378         timersub(&now, &lastupdate, &wait);
  379         if (wait.tv_sec >= STALLTIME)
  380             len += snprintf(buf + len, BUFLEFT, "  (stalled)");
  381     }
  382     len += snprintf(buf + len, BUFLEFT, "\n");
  383     (void)write(siginfo ? STDERR_FILENO : fileno(ttyout), buf, len);
  384 }
  385 
  386 /*
  387  * SIG{INFO,QUIT} handler to print transfer stats if a transfer is in progress
  388  */
  389 void
  390 psummary(int notused)
  391 {
  392     int oerrno = errno;
  393 
  394     if (bytes > 0) {
  395         if (fromatty)
  396             write(fileno(ttyout), "\n", 1);
  397         ptransfer(1);
  398     }
  399     errno = oerrno;
  400 }
  401 #endif  /* !STANDALONE_PROGRESS */
  402 
  403 
  404 /*
  405  * Set the SIGALRM interval timer for wait seconds, 0 to disable.
  406  */
  407 void
  408 alarmtimer(int wait)
  409 {
  410     struct itimerval itv;
  411 
  412     itv.it_value.tv_sec = wait;
  413     itv.it_value.tv_usec = 0;
  414     itv.it_interval = itv.it_value;
  415     setitimer(ITIMER_REAL, &itv, NULL);
  416 }
  417 
  418 
  419 /*
  420  * Install a POSIX signal handler, allowing the invoker to set whether
  421  * the signal should be restartable or not
  422  */
  423 sigfunc
  424 xsignal_restart(int sig, sigfunc func, int restartable)
  425 {
  426 #ifdef ultrix   /* XXX: this is lame - how do we test sigvec vs. sigaction? */
  427     struct sigvec vec, ovec;
  428 
  429     vec.sv_handler = func;
  430     sigemptyset(&vec.sv_mask);
  431     vec.sv_flags = 0;
  432     if (sigvec(sig, &vec, &ovec) < 0)
  433         return (SIG_ERR);
  434     return (ovec.sv_handler);
  435 #else   /* ! ultrix */
  436     struct sigaction act, oact;
  437     act.sa_handler = func;
  438 
  439     sigemptyset(&act.sa_mask);
  440 #if defined(SA_RESTART)         /* 4.4BSD, Posix(?), SVR4 */
  441     act.sa_flags = restartable ? SA_RESTART : 0;
  442 #elif defined(SA_INTERRUPT)     /* SunOS 4.x */
  443     act.sa_flags = restartable ? 0 : SA_INTERRUPT;
  444 #else
  445 #error "system must have SA_RESTART or SA_INTERRUPT"
  446 #endif
  447     if (sigaction(sig, &act, &oact) < 0)
  448         return (SIG_ERR);
  449     return (oact.sa_handler);
  450 #endif  /* ! ultrix */
  451 }
  452 
  453 /*
  454  * Install a signal handler with the `restartable' flag set dependent upon
  455  * which signal is being set. (This is a wrapper to xsignal_restart())
  456  */
  457 sigfunc
  458 xsignal(int sig, sigfunc func)
  459 {
  460     int restartable;
  461 
  462     /*
  463      * Some signals print output or change the state of the process.
  464      * There should be restartable, so that reads and writes are
  465      * not affected.  Some signals should cause program flow to change;
  466      * these signals should not be restartable, so that the system call
  467      * will return with EINTR, and the program will go do something
  468      * different.  If the signal handler calls longjmp() or siglongjmp(),
  469      * it doesn't matter if it's restartable.
  470      */
  471 
  472     switch(sig) {
  473 #ifdef SIGINFO
  474     case SIGINFO:
  475 #endif
  476     case SIGQUIT:
  477     case SIGUSR1:
  478     case SIGUSR2:
  479     case SIGWINCH:
  480         restartable = 1;
  481         break;
  482 
  483     case SIGALRM:
  484     case SIGINT:
  485     case SIGPIPE:
  486         restartable = 0;
  487         break;
  488 
  489     default:
  490         /*
  491          * This is unpleasant, but I don't know what would be better.
  492          * Right now, this "can't happen"
  493          */
  494         errx(1, "xsignal_restart: called with signal %d", sig);
  495     }
  496 
  497     return(xsignal_restart(sig, func, restartable));
  498 }