comparison progressmeter.c @ 330:5488db2e9e4e

merge of 332f709a4cb39cde4cedab7c3be89e05f3023067 and ca4ca78b82c5d430c69ce01bf794e8886ce81431
author Matt Johnston <matt@ucc.asn.au>
date Sat, 10 Jun 2006 16:39:40 +0000
parents b72f98803e46
children
comparison
equal deleted inserted replaced
329:8ed0dce45126 330:5488db2e9e4e
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 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. 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */ 24 */
25 25
26 #include "includes.h" 26 #include "includes.h"
27 /*RCSID("OpenBSD: progressmeter.c,v 1.15 2003/08/31 12:14:22 markus Exp ");*/ 27 /*RCSID("$OpenBSD: progressmeter.c,v 1.24 2005/06/07 13:25:23 jaredy Exp $");*/
28 28
29 #include "progressmeter.h" 29 #include "progressmeter.h"
30 #include "atomicio.h" 30 #include "atomicio.h"
31 #include "scpmisc.h" 31 #include "scpmisc.h"
32 32
41 41
42 /* formats and inserts the specified size into the given buffer */ 42 /* formats and inserts the specified size into the given buffer */
43 static void format_size(char *, int, off_t); 43 static void format_size(char *, int, off_t);
44 static void format_rate(char *, int, off_t); 44 static void format_rate(char *, int, off_t);
45 45
46 /* window resizing */
47 static void sig_winch(int);
48 static void setscreensize(void);
49
46 /* updates the progressmeter to reflect the current state of the transfer */ 50 /* updates the progressmeter to reflect the current state of the transfer */
47 void refresh_progress_meter(void); 51 void refresh_progress_meter(void);
48 52
49 /* signal handler for updating the progress meter */ 53 /* signal handler for updating the progress meter */
50 static void update_progress_meter(int); 54 static void update_progress_meter(int);
51 55
52 static time_t start; /* start progress */ 56 static time_t start; /* start progress */
53 static time_t last_update; /* last progress update */ 57 static time_t last_update; /* last progress update */
54 static char *file; /* name of the file being transferred */ 58 static char *file; /* name of the file being transferred */
55 static off_t end_pos; /* ending position of transfer */ 59 static off_t end_pos; /* ending position of transfer */
56 static off_t cur_pos; /* transfer position as of last refresh */ 60 static off_t cur_pos; /* transfer position as of last refresh */
57 static volatile off_t *counter; /* progress counter */ 61 static volatile off_t *counter; /* progress counter */
58 static long stalled; /* how long we have been stalled */ 62 static long stalled; /* how long we have been stalled */
59 static int bytes_per_second; /* current speed in bytes per second */ 63 static int bytes_per_second; /* current speed in bytes per second */
60 static int win_size; /* terminal window size */ 64 static int win_size; /* terminal window size */
65 static volatile sig_atomic_t win_resized; /* for window resizing */
61 66
62 /* units for format_size */ 67 /* units for format_size */
63 static const char unit[] = " KMGT"; 68 static const char unit[] = " KMGT";
64 69
65 static int 70 static int
79 if (i == 0) { 84 if (i == 0) {
80 i++; 85 i++;
81 bytes = (bytes + 512) / 1024; 86 bytes = (bytes + 512) / 1024;
82 } 87 }
83 snprintf(buf, size, "%3lld.%1lld%c%s", 88 snprintf(buf, size, "%3lld.%1lld%c%s",
84 (int64_t) bytes / 100, 89 (long long) (bytes + 5) / 100,
85 (int64_t) (bytes + 5) / 10 % 10, 90 (long long) (bytes + 5) / 10 % 10,
86 unit[i], 91 unit[i],
87 i ? "B" : " "); 92 i ? "B" : " ");
88 } 93 }
89 94
90 static void 95 static void
93 int i; 98 int i;
94 99
95 for (i = 0; bytes >= 10000 && unit[i] != 'T'; i++) 100 for (i = 0; bytes >= 10000 && unit[i] != 'T'; i++)
96 bytes = (bytes + 512) / 1024; 101 bytes = (bytes + 512) / 1024;
97 snprintf(buf, size, "%4lld%c%s", 102 snprintf(buf, size, "%4lld%c%s",
98 (int64_t) bytes, 103 (long long) bytes,
99 unit[i], 104 unit[i],
100 i ? "B" : " "); 105 i ? "B" : " ");
101 } 106 }
102 107
103 void 108 void
106 char buf[MAX_WINSIZE + 1]; 111 char buf[MAX_WINSIZE + 1];
107 time_t now; 112 time_t now;
108 off_t transferred; 113 off_t transferred;
109 double elapsed; 114 double elapsed;
110 int percent; 115 int percent;
111 int bytes_left; 116 off_t bytes_left;
112 int cur_speed; 117 int cur_speed;
113 int hours, minutes, seconds; 118 int hours, minutes, seconds;
114 int i, len; 119 int i, len;
115 int file_len; 120 int file_len;
116 121
119 now = time(NULL); 124 now = time(NULL);
120 bytes_left = end_pos - cur_pos; 125 bytes_left = end_pos - cur_pos;
121 126
122 if (bytes_left > 0) 127 if (bytes_left > 0)
123 elapsed = now - last_update; 128 elapsed = now - last_update;
124 else 129 else {
125 elapsed = now - start; 130 elapsed = now - start;
131 /* Calculate true total speed when done */
132 transferred = end_pos;
133 bytes_per_second = 0;
134 }
126 135
127 /* calculate speed */ 136 /* calculate speed */
128 if (elapsed != 0) 137 if (elapsed != 0)
129 cur_speed = (transferred / elapsed); 138 cur_speed = (transferred / elapsed);
130 else 139 else
131 cur_speed = 0; 140 cur_speed = transferred;
132 141
133 #define AGE_FACTOR 0.9 142 #define AGE_FACTOR 0.9
134 if (bytes_per_second != 0) { 143 if (bytes_per_second != 0) {
135 bytes_per_second = (bytes_per_second * AGE_FACTOR) + 144 bytes_per_second = (bytes_per_second * AGE_FACTOR) +
136 (cur_speed * (1.0 - AGE_FACTOR)); 145 (cur_speed * (1.0 - AGE_FACTOR));
142 file_len = win_size - 35; 151 file_len = win_size - 35;
143 if (file_len > 0) { 152 if (file_len > 0) {
144 len = snprintf(buf, file_len + 1, "\r%s", file); 153 len = snprintf(buf, file_len + 1, "\r%s", file);
145 if (len < 0) 154 if (len < 0)
146 len = 0; 155 len = 0;
156 if (len >= file_len + 1)
157 len = file_len;
147 for (i = len; i < file_len; i++ ) 158 for (i = len; i < file_len; i++ )
148 buf[i] = ' '; 159 buf[i] = ' ';
149 buf[file_len] = '\0'; 160 buf[file_len] = '\0';
150 } 161 }
151 162
162 cur_pos); 173 cur_pos);
163 strlcat(buf, " ", win_size); 174 strlcat(buf, " ", win_size);
164 175
165 /* bandwidth usage */ 176 /* bandwidth usage */
166 format_rate(buf + strlen(buf), win_size - strlen(buf), 177 format_rate(buf + strlen(buf), win_size - strlen(buf),
167 bytes_per_second); 178 (off_t)bytes_per_second);
168 strlcat(buf, "/s ", win_size); 179 strlcat(buf, "/s ", win_size);
169 180
170 /* ETA */ 181 /* ETA */
171 if (!transferred) 182 if (!transferred)
172 stalled += elapsed; 183 stalled += elapsed;
199 strlcat(buf, " ETA", win_size); 210 strlcat(buf, " ETA", win_size);
200 else 211 else
201 strlcat(buf, " ", win_size); 212 strlcat(buf, " ", win_size);
202 } 213 }
203 214
204 atomicio(vwrite, STDOUT_FILENO, buf, win_size); 215 atomicio(vwrite, STDOUT_FILENO, buf, win_size - 1);
205 last_update = now; 216 last_update = now;
206 } 217 }
207 218
208 static void 219 static void
209 update_progress_meter(int ignore) 220 update_progress_meter(int ignore)
210 { 221 {
211 int save_errno; 222 int save_errno;
212 223
213 save_errno = errno; 224 save_errno = errno;
214 225
226 if (win_resized) {
227 setscreensize();
228 win_resized = 0;
229 }
215 if (can_output()) 230 if (can_output())
216 refresh_progress_meter(); 231 refresh_progress_meter();
217 232
218 signal(SIGALRM, update_progress_meter); 233 signal(SIGALRM, update_progress_meter);
219 alarm(UPDATE_INTERVAL); 234 alarm(UPDATE_INTERVAL);
220 errno = save_errno; 235 errno = save_errno;
221 } 236 }
222 237
223 void 238 void
224 start_progress_meter(char *f, off_t filesize, off_t *stat) 239 start_progress_meter(char *f, off_t filesize, off_t *ctr)
225 { 240 {
226 struct winsize winsize;
227
228 start = last_update = time(NULL); 241 start = last_update = time(NULL);
229 file = f; 242 file = f;
230 end_pos = filesize; 243 end_pos = filesize;
231 cur_pos = 0; 244 cur_pos = 0;
232 counter = stat; 245 counter = ctr;
233 stalled = 0; 246 stalled = 0;
234 bytes_per_second = 0; 247 bytes_per_second = 0;
248
249 setscreensize();
250 if (can_output())
251 refresh_progress_meter();
252
253 signal(SIGALRM, update_progress_meter);
254 signal(SIGWINCH, sig_winch);
255 alarm(UPDATE_INTERVAL);
256 }
257
258 void
259 stop_progress_meter(void)
260 {
261 alarm(0);
262
263 if (!can_output())
264 return;
265
266 /* Ensure we complete the progress */
267 if (cur_pos != end_pos)
268 refresh_progress_meter();
269
270 atomicio(vwrite, STDOUT_FILENO, "\n", 1);
271 }
272
273 static void
274 sig_winch(int sig)
275 {
276 win_resized = 1;
277 }
278
279 static void
280 setscreensize(void)
281 {
282 struct winsize winsize;
235 283
236 if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &winsize) != -1 && 284 if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &winsize) != -1 &&
237 winsize.ws_col != 0) { 285 winsize.ws_col != 0) {
238 if (winsize.ws_col > MAX_WINSIZE) 286 if (winsize.ws_col > MAX_WINSIZE)
239 win_size = MAX_WINSIZE; 287 win_size = MAX_WINSIZE;
240 else 288 else
241 win_size = winsize.ws_col; 289 win_size = winsize.ws_col;
242 } else 290 } else
243 win_size = DEFAULT_WINSIZE; 291 win_size = DEFAULT_WINSIZE;
244 win_size += 1; /* trailing \0 */ 292 win_size += 1; /* trailing \0 */
245
246 if (can_output())
247 refresh_progress_meter();
248
249 signal(SIGALRM, update_progress_meter);
250 alarm(UPDATE_INTERVAL);
251 }
252
253 void
254 stop_progress_meter(void)
255 {
256 alarm(0);
257
258 if (!can_output())
259 return;
260
261 /* Ensure we complete the progress */
262 if (cur_pos != end_pos)
263 refresh_progress_meter();
264
265 atomicio(vwrite, STDOUT_FILENO, "\n", 1);
266 } 293 }
267 #endif /* PROGRESS_METER */ 294 #endif /* PROGRESS_METER */