11305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* $OpenBSD: progressmeter.c,v 1.37 2006/08/03 03:34:42 deraadt Exp $ */
21305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/*
31305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * Copyright (c) 2003 Nils Nordman.  All rights reserved.
41305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood *
51305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * Redistribution and use in source and binary forms, with or without
61305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * modification, are permitted provided that the following conditions
71305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * are met:
81305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * 1. Redistributions of source code must retain the above copyright
91305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood *    notice, this list of conditions and the following disclaimer.
101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * 2. Redistributions in binary form must reproduce the above copyright
111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood *    notice, this list of conditions and the following disclaimer in the
121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood *    documentation and/or other materials provided with the distribution.
131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood *
141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood */
251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include "includes.h"
271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <sys/types.h>
291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <sys/ioctl.h>
301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <sys/uio.h>
311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <errno.h>
331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <signal.h>
341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <stdio.h>
351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <string.h>
361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <time.h>
371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <unistd.h>
381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include "progressmeter.h"
401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include "atomicio.h"
411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include "misc.h"
421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define DEFAULT_WINSIZE 80
441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define MAX_WINSIZE 512
451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define PADDING 1		/* padding between the progress indicators */
461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define UPDATE_INTERVAL 1	/* update the progress meter every second */
471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define STALL_TIME 5		/* we're stalled after this many seconds */
481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* determines whether we can output to the terminal */
501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic int can_output(void);
511305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
521305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* formats and inserts the specified size into the given buffer */
531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic void format_size(char *, int, off_t);
541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic void format_rate(char *, int, off_t);
551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* window resizing */
571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic void sig_winch(int);
581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic void setscreensize(void);
591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* updates the progressmeter to reflect the current state of the transfer */
611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodvoid refresh_progress_meter(void);
621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* signal handler for updating the progress meter */
641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic void update_progress_meter(int);
651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic time_t start;		/* start progress */
671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic time_t last_update;	/* last progress update */
681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic char *file;		/* name of the file being transferred */
691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic off_t end_pos;		/* ending position of transfer */
701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic off_t cur_pos;		/* transfer position as of last refresh */
711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic volatile off_t *counter;	/* progress counter */
721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic long stalled;		/* how long we have been stalled */
731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic int bytes_per_second;	/* current speed in bytes per second */
741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic int win_size;		/* terminal window size */
751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic volatile sig_atomic_t win_resized; /* for window resizing */
761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* units for format_size */
781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic const char unit[] = " KMGT";
791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic int
811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodcan_output(void)
821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	return (getpgrp() == tcgetpgrp(STDOUT_FILENO));
841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic void
871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodformat_rate(char *buf, int size, off_t bytes)
881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	int i;
901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	bytes *= 100;
921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	for (i = 0; bytes >= 100*1000 && unit[i] != 'T'; i++)
931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		bytes = (bytes + 512) / 1024;
941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (i == 0) {
951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		i++;
961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		bytes = (bytes + 512) / 1024;
971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
981305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	snprintf(buf, size, "%3lld.%1lld%c%s",
991305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    (long long) (bytes + 5) / 100,
1001305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    (long long) (bytes + 5) / 10 % 10,
1011305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    unit[i],
1021305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    i ? "B" : " ");
1031305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
1041305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
1051305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic void
1061305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodformat_size(char *buf, int size, off_t bytes)
1071305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
1081305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	int i;
1091305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
1101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	for (i = 0; bytes >= 10000 && unit[i] != 'T'; i++)
1111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		bytes = (bytes + 512) / 1024;
1121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	snprintf(buf, size, "%4lld%c%s",
1131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    (long long) bytes,
1141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    unit[i],
1151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    i ? "B" : " ");
1161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
1171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
1181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodvoid
1191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodrefresh_progress_meter(void)
1201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
1211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	char buf[MAX_WINSIZE + 1];
1221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	time_t now;
1231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	off_t transferred;
1241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	double elapsed;
1251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	int percent;
1261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	off_t bytes_left;
1271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	int cur_speed;
1281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	int hours, minutes, seconds;
1291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	int i, len;
1301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	int file_len;
1311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
1321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	transferred = *counter - cur_pos;
1331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	cur_pos = *counter;
1341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	now = time(NULL);
1351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	bytes_left = end_pos - cur_pos;
1361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
1371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (bytes_left > 0)
1381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		elapsed = now - last_update;
1391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	else {
1401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		elapsed = now - start;
1411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		/* Calculate true total speed when done */
1421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		transferred = end_pos;
1431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		bytes_per_second = 0;
1441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
1451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
1461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* calculate speed */
1471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (elapsed != 0)
1481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		cur_speed = (transferred / elapsed);
1491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	else
1501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		cur_speed = transferred;
1511305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
1521305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define AGE_FACTOR 0.9
1531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (bytes_per_second != 0) {
1541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		bytes_per_second = (bytes_per_second * AGE_FACTOR) +
1551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		    (cur_speed * (1.0 - AGE_FACTOR));
1561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	} else
1571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		bytes_per_second = cur_speed;
1581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
1591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* filename */
1601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	buf[0] = '\0';
1611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	file_len = win_size - 35;
1621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (file_len > 0) {
1631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		len = snprintf(buf, file_len + 1, "\r%s", file);
1641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (len < 0)
1651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			len = 0;
1661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (len >= file_len + 1)
1671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			len = file_len;
1681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		for (i = len; i < file_len; i++)
1691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			buf[i] = ' ';
1701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		buf[file_len] = '\0';
1711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
1721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
1731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* percent of transfer done */
1741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (end_pos != 0)
1751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		percent = ((float)cur_pos / end_pos) * 100;
1761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	else
1771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		percent = 100;
1781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	snprintf(buf + strlen(buf), win_size - strlen(buf),
1791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    " %3d%% ", percent);
1801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
1811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* amount transferred */
1821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	format_size(buf + strlen(buf), win_size - strlen(buf),
1831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    cur_pos);
1841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	strlcat(buf, " ", win_size);
1851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
1861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* bandwidth usage */
1871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	format_rate(buf + strlen(buf), win_size - strlen(buf),
1881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    (off_t)bytes_per_second);
1891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	strlcat(buf, "/s ", win_size);
1901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
1911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* ETA */
1921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (!transferred)
1931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		stalled += elapsed;
1941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	else
1951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		stalled = 0;
1961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
1971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (stalled >= STALL_TIME)
1981305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		strlcat(buf, "- stalled -", win_size);
1991305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	else if (bytes_per_second == 0 && bytes_left)
2001305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		strlcat(buf, "  --:-- ETA", win_size);
2011305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	else {
2021305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (bytes_left > 0)
2031305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			seconds = bytes_left / bytes_per_second;
2041305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		else
2051305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			seconds = elapsed;
2061305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
2071305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		hours = seconds / 3600;
2081305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		seconds -= hours * 3600;
2091305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		minutes = seconds / 60;
2101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		seconds -= minutes * 60;
2111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
2121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (hours != 0)
2131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			snprintf(buf + strlen(buf), win_size - strlen(buf),
2141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			    "%d:%02d:%02d", hours, minutes, seconds);
2151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		else
2161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			snprintf(buf + strlen(buf), win_size - strlen(buf),
2171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			    "  %02d:%02d", minutes, seconds);
2181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
2191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (bytes_left > 0)
2201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			strlcat(buf, " ETA", win_size);
2211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		else
2221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			strlcat(buf, "    ", win_size);
2231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
2241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
2251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	atomicio(vwrite, STDOUT_FILENO, buf, win_size - 1);
2261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	last_update = now;
2271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
2281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
2291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/*ARGSUSED*/
2301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic void
2311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodupdate_progress_meter(int ignore)
2321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
2331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	int save_errno;
2341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
2351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	save_errno = errno;
2361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
2371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (win_resized) {
2381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		setscreensize();
2391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		win_resized = 0;
2401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
2411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (can_output())
2421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		refresh_progress_meter();
2431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
2441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	signal(SIGALRM, update_progress_meter);
2451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	alarm(UPDATE_INTERVAL);
2461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	errno = save_errno;
2471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
2481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
2491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodvoid
2501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstart_progress_meter(char *f, off_t filesize, off_t *ctr)
2511305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
2521305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	start = last_update = time(NULL);
2531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	file = f;
2541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	end_pos = filesize;
2551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	cur_pos = 0;
2561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	counter = ctr;
2571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	stalled = 0;
2581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	bytes_per_second = 0;
2591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
2601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	setscreensize();
2611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (can_output())
2621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		refresh_progress_meter();
2631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
2641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	signal(SIGALRM, update_progress_meter);
2651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	signal(SIGWINCH, sig_winch);
2661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	alarm(UPDATE_INTERVAL);
2671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
2681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
2691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodvoid
2701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstop_progress_meter(void)
2711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
2721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	alarm(0);
2731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
2741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (!can_output())
2751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		return;
2761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
2771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* Ensure we complete the progress */
2781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (cur_pos != end_pos)
2791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		refresh_progress_meter();
2801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
2811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	atomicio(vwrite, STDOUT_FILENO, "\n", 1);
2821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
2831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
2841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/*ARGSUSED*/
2851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic void
2861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodsig_winch(int sig)
2871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
2881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	win_resized = 1;
2891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
2901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
2911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic void
2921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodsetscreensize(void)
2931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
2941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	struct winsize winsize;
2951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
2961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &winsize) != -1 &&
2971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    winsize.ws_col != 0) {
2981305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (winsize.ws_col > MAX_WINSIZE)
2991305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			win_size = MAX_WINSIZE;
3001305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		else
3011305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			win_size = winsize.ws_col;
3021305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	} else
3031305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		win_size = DEFAULT_WINSIZE;
3041305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	win_size += 1;					/* trailing \0 */
3051305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
306