#include "tnftp.h"
#if 0
#include <sys/cdefs.h>
#ifndef lint
__RCSID(" NetBSD: progressbar.c,v 1.17 2007/05/05 18:09:24 martin Exp ");
#endif
#include <sys/types.h>
#include <sys/param.h>
#include <err.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <tzfile.h>
#include <unistd.h>
#endif
#include "progressbar.h"
#if !defined(NO_PROGRESS)
int
foregroundproc(void)
{
static pid_t pgrp = -1;
if (pgrp == -1)
#if GETPGRP_VOID
pgrp = getpgrp();
#else
pgrp = getpgrp(0);
#endif
return (tcgetpgrp(fileno(ttyout)) == pgrp);
}
#endif
static void updateprogressmeter(int);
static void
updateprogressmeter(int dummy)
{
int oerrno = errno;
progressmeter(0);
errno = oerrno;
}
static const char * const suffixes[] = {
"",
"KiB",
"MiB",
"GiB",
"TiB",
"PiB",
"EiB",
#if 0
"ZiB",
"YiB",
#endif
};
#define NSUFFIXES (sizeof(suffixes) / sizeof(suffixes[0]))
static struct timeval start;
static struct timeval lastupdate;
#define BUFLEFT (sizeof(buf) - len)
void
progressmeter(int flag)
{
static off_t lastsize;
off_t cursize;
struct timeval now, wait;
#ifndef NO_PROGRESS
struct timeval td;
off_t abbrevsize, bytespersec;
double elapsed;
int ratio, i, remaining, barlength;
#endif
size_t len;
char buf[256];
#ifndef NO_PROGRESS
#define BAROVERHEAD 45
static const char stars[] =
"*****************************************************************************"
"*****************************************************************************"
"*****************************************************************************";
#endif
if (flag == -1) {
(void)gettimeofday(&start, NULL);
lastupdate = start;
lastsize = restart_point;
}
(void)gettimeofday(&now, NULL);
cursize = bytes + restart_point;
timersub(&now, &lastupdate, &wait);
if (cursize > lastsize) {
lastupdate = now;
lastsize = cursize;
wait.tv_sec = 0;
} else {
#ifndef STANDALONE_PROGRESS
if (quit_time > 0 && wait.tv_sec > quit_time) {
len = snprintf(buf, sizeof(buf), "\r\n%s: "
"transfer aborted because stalled for %lu sec.\r\n",
getprogname(), (unsigned long)wait.tv_sec);
(void)write(fileno(ttyout), buf, len);
(void)xsignal(SIGALRM, SIG_DFL);
alarmtimer(0);
siglongjmp(toplevel, 1);
}
#endif
}
#ifdef STANDALONE_PROGRESS
if (progress) {
#else
if (quit_time > 0 || progress) {
#endif
if (flag == -1) {
(void)xsignal_restart(SIGALRM, updateprogressmeter, 1);
alarmtimer(1);
} else if (flag == 1) {
(void)xsignal(SIGALRM, SIG_DFL);
alarmtimer(0);
}
}
#ifndef NO_PROGRESS
if (!progress)
return;
len = 0;
if (! foregroundproc())
return;
len += snprintf(buf + len, BUFLEFT, "\r");
if (prefix)
len += snprintf(buf + len, BUFLEFT, "%s", prefix);
if (filesize > 0) {
ratio = (int)((double)cursize * 100.0 / (double)filesize);
ratio = MAX(ratio, 0);
ratio = MIN(ratio, 100);
len += snprintf(buf + len, BUFLEFT, "%3d%% ", ratio);
barlength = MIN(sizeof(buf) - 1, ttywidth) - BAROVERHEAD;
if (prefix)
barlength -= (int)strlen(prefix);
if (barlength > 0) {
i = barlength * ratio / 100;
len += snprintf(buf + len, BUFLEFT,
"|%.*s%*s|", i, stars, (int)(barlength - i), "");
}
}
abbrevsize = cursize;
for (i = 0; abbrevsize >= 100000 && i < NSUFFIXES; i++)
abbrevsize >>= 10;
if (i == NSUFFIXES)
i--;
len += snprintf(buf + len, BUFLEFT, " " LLFP("5") " %-3s ",
(LLT)abbrevsize,
suffixes[i]);
timersub(&now, &start, &td);
elapsed = td.tv_sec + (td.tv_usec / 1000000.0);
bytespersec = 0;
if (bytes > 0) {
bytespersec = bytes;
if (elapsed > 0.0)
bytespersec /= elapsed;
}
for (i = 1; bytespersec >= 1024000 && i < NSUFFIXES; i++)
bytespersec >>= 10;
len += snprintf(buf + len, BUFLEFT,
" " LLFP("3") ".%02d %.2sB/s ",
(LLT)(bytespersec / 1024),
(int)((bytespersec % 1024) * 100 / 1024),
suffixes[i]);
if (filesize > 0) {
if (bytes <= 0 || elapsed <= 0.0 || cursize > filesize) {
len += snprintf(buf + len, BUFLEFT, " --:-- ETA");
} else if (wait.tv_sec >= STALLTIME) {
len += snprintf(buf + len, BUFLEFT, " - stalled -");
} else {
remaining = (int)
((filesize - restart_point) / (bytes / elapsed) -
elapsed);
if (remaining >= 100 * SECSPERHOUR)
len += snprintf(buf + len, BUFLEFT,
" --:-- ETA");
else {
i = remaining / SECSPERHOUR;
if (i)
len += snprintf(buf + len, BUFLEFT,
"%2d:", i);
else
len += snprintf(buf + len, BUFLEFT,
" ");
i = remaining % SECSPERHOUR;
len += snprintf(buf + len, BUFLEFT,
"%02d:%02d ETA", i / 60, i % 60);
}
}
}
if (flag == 1)
len += snprintf(buf + len, BUFLEFT, "\n");
(void)write(fileno(ttyout), buf, len);
#endif
}
#ifndef STANDALONE_PROGRESS
void
ptransfer(int siginfo)
{
struct timeval now, td, wait;
double elapsed;
off_t bytespersec;
int remaining, hh, i;
size_t len;
char buf[256];
if (!verbose && !progress && !siginfo)
return;
(void)gettimeofday(&now, NULL);
timersub(&now, &start, &td);
elapsed = td.tv_sec + (td.tv_usec / 1000000.0);
bytespersec = 0;
if (bytes > 0) {
bytespersec = bytes;
if (elapsed > 0.0)
bytespersec /= elapsed;
}
len = 0;
len += snprintf(buf + len, BUFLEFT, LLF " byte%s %s in ",
(LLT)bytes, bytes == 1 ? "" : "s", direction);
remaining = (int)elapsed;
if (remaining > SECSPERDAY) {
int days;
days = remaining / SECSPERDAY;
remaining %= SECSPERDAY;
len += snprintf(buf + len, BUFLEFT,
"%d day%s ", days, days == 1 ? "" : "s");
}
hh = remaining / SECSPERHOUR;
remaining %= SECSPERHOUR;
if (hh)
len += snprintf(buf + len, BUFLEFT, "%2d:", hh);
len += snprintf(buf + len, BUFLEFT,
"%02d:%02d ", remaining / 60, remaining % 60);
for (i = 1; bytespersec >= 1024000 && i < NSUFFIXES; i++)
bytespersec >>= 10;
if (i == NSUFFIXES)
i--;
len += snprintf(buf + len, BUFLEFT, "(" LLF ".%02d %.2sB/s)",
(LLT)(bytespersec / 1024),
(int)((bytespersec % 1024) * 100 / 1024),
suffixes[i]);
if (siginfo && bytes > 0 && elapsed > 0.0 && filesize >= 0
&& bytes + restart_point <= filesize) {
remaining = (int)((filesize - restart_point) /
(bytes / elapsed) - elapsed);
hh = remaining / SECSPERHOUR;
remaining %= SECSPERHOUR;
len += snprintf(buf + len, BUFLEFT, " ETA: ");
if (hh)
len += snprintf(buf + len, BUFLEFT, "%2d:", hh);
len += snprintf(buf + len, BUFLEFT, "%02d:%02d",
remaining / 60, remaining % 60);
timersub(&now, &lastupdate, &wait);
if (wait.tv_sec >= STALLTIME)
len += snprintf(buf + len, BUFLEFT, " (stalled)");
}
len += snprintf(buf + len, BUFLEFT, "\n");
(void)write(siginfo ? STDERR_FILENO : fileno(ttyout), buf, len);
}
void
psummary(int notused)
{
int oerrno = errno;
if (bytes > 0) {
if (fromatty)
write(fileno(ttyout), "\n", 1);
ptransfer(1);
}
errno = oerrno;
}
#endif
void
alarmtimer(int wait)
{
struct itimerval itv;
itv.it_value.tv_sec = wait;
itv.it_value.tv_usec = 0;
itv.it_interval = itv.it_value;
setitimer(ITIMER_REAL, &itv, NULL);
}
sigfunc
xsignal_restart(int sig, sigfunc func, int restartable)
{
#ifdef ultrix
struct sigvec vec, ovec;
vec.sv_handler = func;
sigemptyset(&vec.sv_mask);
vec.sv_flags = 0;
if (sigvec(sig, &vec, &ovec) < 0)
return (SIG_ERR);
return (ovec.sv_handler);
#else
struct sigaction act, oact;
act.sa_handler = func;
sigemptyset(&act.sa_mask);
#if defined(SA_RESTART)
act.sa_flags = restartable ? SA_RESTART : 0;
#elif defined(SA_INTERRUPT)
act.sa_flags = restartable ? 0 : SA_INTERRUPT;
#else
#error "system must have SA_RESTART or SA_INTERRUPT"
#endif
if (sigaction(sig, &act, &oact) < 0)
return (SIG_ERR);
return (oact.sa_handler);
#endif
}
sigfunc
xsignal(int sig, sigfunc func)
{
int restartable;
switch(sig) {
#ifdef SIGINFO
case SIGINFO:
#endif
case SIGQUIT:
case SIGUSR1:
case SIGUSR2:
case SIGWINCH:
restartable = 1;
break;
case SIGALRM:
case SIGINT:
case SIGPIPE:
restartable = 0;
break;
default:
errx(1, "xsignal_restart: called with signal %d", sig);
}
return(xsignal_restart(sig, func, restartable));
}