summaryrefslogtreecommitdiff
path: root/progressmeter.c
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2003-01-10 21:46:02 +1100
committerDamien Miller <djm@mindrot.org>2003-01-10 21:46:02 +1100
commit6fd00e042c13dfd94cdcaef5b4d1656d900b8ce6 (patch)
treeacb5c9be53516337abe9a9133ecbcd2a420f745d /progressmeter.c
parentb46b9f322d82a7c912e6e15dbd8a73261acf2991 (diff)
- fgsch@cvs.openbsd.org 2003/01/10 08:19:07
[scp.c sftp.1 sftp.c sftp-client.c sftp-int.c progressmeter.c] [progressmeter.h] sftp progress meter support. original diffs by Nils Nordman <nino at nforced dot com> via markus@, merged to -current by me, djm@ ok.
Diffstat (limited to 'progressmeter.c')
-rw-r--r--progressmeter.c256
1 files changed, 256 insertions, 0 deletions
diff --git a/progressmeter.c b/progressmeter.c
new file mode 100644
index 000000000..ae13c67e7
--- /dev/null
+++ b/progressmeter.c
@@ -0,0 +1,256 @@
1/*
2 * Copyright (c) 1999 Theo de Raadt. All rights reserved.
3 * Copyright (c) 1999 Aaron Campbell. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26/*
27 * Parts from:
28 *
29 * Copyright (c) 1983, 1990, 1992, 1993, 1995
30 * The Regents of the University of California. All rights reserved.
31 *
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
34 * are met:
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
40 * 3. All advertising materials mentioning features or use of this software
41 * must display the following acknowledgement:
42 * This product includes software developed by the University of
43 * California, Berkeley and its contributors.
44 * 4. Neither the name of the University nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
59 *
60 */
61
62#include "includes.h"
63RCSID("$OpenBSD: progressmeter.c,v 1.1 2003/01/10 08:19:07 fgsch Exp $");
64
65#include <libgen.h>
66
67#include "atomicio.h"
68
69/* Number of seconds before xfer considered "stalled". */
70#define STALLTIME 5
71/* alarm() interval for updating progress meter. */
72#define PROGRESSTIME 1
73
74/* Signal handler used for updating the progress meter. */
75static void update_progress_meter(int);
76
77/* Returns non-zero if we are the foreground process. */
78static int foregroundproc(void);
79
80/* Returns width of the terminal (for progress meter calculations). */
81static int get_tty_width(void);
82
83/* Visual statistics about files as they are transferred. */
84static void draw_progress_meter();
85
86/* Time a transfer started. */
87static struct timeval start;
88
89/* Number of bytes of current file transferred so far. */
90static volatile off_t *statbytes;
91
92/* Total size of current file. */
93static off_t totalbytes;
94
95/* Name of current file being transferred. */
96static char *curfile;
97
98/* Time of last update. */
99static struct timeval lastupdate;
100
101/* Size at the time of the last update. */
102static off_t lastsize;
103
104void
105start_progress_meter(char *file, off_t filesize, off_t *counter)
106{
107 if ((curfile = basename(file)) == NULL)
108 curfile = file;
109
110 totalbytes = filesize;
111 statbytes = counter;
112 (void) gettimeofday(&start, (struct timezone *) 0);
113 lastupdate = start;
114 lastsize = 0;
115
116 draw_progress_meter();
117 signal(SIGALRM, update_progress_meter);
118 alarm(PROGRESSTIME);
119}
120
121void
122stop_progress_meter()
123{
124 alarm(0);
125 draw_progress_meter();
126 atomicio(write, fileno(stdout), "\n", 1);
127}
128
129static void
130update_progress_meter(int ignore)
131{
132 int save_errno = errno;
133
134 draw_progress_meter();
135 signal(SIGALRM, update_progress_meter);
136 alarm(PROGRESSTIME);
137 errno = save_errno;
138}
139
140static int
141foregroundproc(void)
142{
143 static pid_t pgrp = -1;
144 int ctty_pgrp;
145
146 if (pgrp == -1)
147 pgrp = getpgrp();
148
149 return ((ioctl(STDOUT_FILENO, TIOCGPGRP, &ctty_pgrp) != -1 &&
150 ctty_pgrp == pgrp));
151}
152
153static void
154draw_progress_meter()
155{
156 static const char spaces[] = " "
157 " "
158 " "
159 " "
160 " "
161 " ";
162 static const char prefixes[] = " KMGTP";
163 struct timeval now, td, wait;
164 off_t cursize, abbrevsize, bytespersec;
165 double elapsed;
166 int ratio, remaining, i, ai, bi, nspaces;
167 char buf[512];
168
169 if (foregroundproc() == 0)
170 return;
171
172 (void) gettimeofday(&now, (struct timezone *) 0);
173 cursize = *statbytes;
174 if (totalbytes != 0) {
175 ratio = 100.0 * cursize / totalbytes;
176 ratio = MAX(ratio, 0);
177 ratio = MIN(ratio, 100);
178 } else
179 ratio = 100;
180
181 abbrevsize = cursize;
182 for (ai = 0; abbrevsize >= 10000 && ai < sizeof(prefixes); ai++)
183 abbrevsize >>= 10;
184
185 timersub(&now, &lastupdate, &wait);
186 if (cursize > lastsize) {
187 lastupdate = now;
188 lastsize = cursize;
189 wait.tv_sec = 0;
190 }
191 timersub(&now, &start, &td);
192 elapsed = td.tv_sec + (td.tv_usec / 1000000.0);
193
194 bytespersec = 0;
195 if (cursize > 0) {
196 bytespersec = cursize;
197 if (elapsed > 0.0)
198 bytespersec /= elapsed;
199 }
200 for (bi = 1; bytespersec >= 1024000 && bi < sizeof(prefixes); bi++)
201 bytespersec >>= 10;
202
203 nspaces = MIN(get_tty_width() - 79, sizeof(spaces) - 1);
204
205 snprintf(buf, sizeof(buf),
206 "\r%-45.45s%.*s%3d%% %4lld%c%c %3lld.%01d%cB/s",
207 curfile,
208 nspaces,
209 spaces,
210 ratio,
211 (long long)abbrevsize,
212 prefixes[ai],
213 ai == 0 ? ' ' : 'B',
214 (long long)(bytespersec / 1024),
215 (int)((bytespersec % 1024) * 10 / 1024),
216 prefixes[bi]
217 );
218
219 if (cursize <= 0 || elapsed <= 0.0 || cursize > totalbytes) {
220 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
221 " --:-- ETA");
222 } else if (wait.tv_sec >= STALLTIME) {
223 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
224 " - stalled -");
225 } else {
226 if (cursize != totalbytes)
227 remaining = (int)(totalbytes / (cursize / elapsed) -
228 elapsed);
229 else
230 remaining = elapsed;
231
232 i = remaining / 3600;
233 if (i)
234 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
235 "%2d:", i);
236 else
237 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
238 " ");
239 i = remaining % 3600;
240 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
241 "%02d:%02d%s", i / 60, i % 60,
242 (cursize != totalbytes) ? " ETA" : " ");
243 }
244 atomicio(write, fileno(stdout), buf, strlen(buf));
245}
246
247static int
248get_tty_width(void)
249{
250 struct winsize winsize;
251
252 if (ioctl(fileno(stdout), TIOCGWINSZ, &winsize) != -1)
253 return (winsize.ws_col ? winsize.ws_col : 80);
254 else
255 return (80);
256}