Lines 85-90
static int t_flag; /*! -t: workaround TCP bug *
Link Here
|
85 |
static int U_flag; /* -U: do not use high ports */ |
85 |
static int U_flag; /* -U: do not use high ports */ |
86 |
static int v_level = 1; /* -v: verbosity level */ |
86 |
static int v_level = 1; /* -v: verbosity level */ |
87 |
static int v_tty; /* stdout is a tty */ |
87 |
static int v_tty; /* stdout is a tty */ |
|
|
88 |
static int v_progress; /* whether to display progress */ |
88 |
static pid_t pgrp; /* our process group */ |
89 |
static pid_t pgrp; /* our process group */ |
89 |
static long w_secs; /* -w: retry delay */ |
90 |
static long w_secs; /* -w: retry delay */ |
90 |
static int family = PF_UNSPEC; /* -[46]: address family to use */ |
91 |
static int family = PF_UNSPEC; /* -[46]: address family to use */ |
Lines 199-227
struct xferstat {
Link Here
|
199 |
}; |
200 |
}; |
200 |
|
201 |
|
201 |
/* |
202 |
/* |
|
|
203 |
* Format a number of seconds as either XXdYYh, XXhYYm, XXmYYs, or XXs |
204 |
* depending on its magnitude |
205 |
*/ |
206 |
static void |
207 |
stat_seconds(char *str, size_t strsz, time_t seconds) |
208 |
{ |
209 |
|
210 |
if (seconds > 86400) |
211 |
snprintf(str, strsz, "%02ldd%02ldh", |
212 |
seconds / 86400, (seconds % 86400) / 3600); |
213 |
else if (seconds > 3600) |
214 |
snprintf(str, strsz, "%02ldh%02ldm", |
215 |
seconds / 3600, (seconds % 3600) / 60); |
216 |
else if (seconds > 60) |
217 |
snprintf(str, strsz, "%02ldm%02lds", |
218 |
seconds / 60, seconds % 60); |
219 |
else |
220 |
snprintf(str, strsz, " %02lds", |
221 |
seconds); |
222 |
} |
223 |
|
224 |
/* |
202 |
* Compute and display ETA |
225 |
* Compute and display ETA |
203 |
*/ |
226 |
*/ |
204 |
static const char * |
227 |
static void |
205 |
stat_eta(struct xferstat *xs) |
228 |
stat_eta(char *str, size_t strsz, const struct xferstat *xs) |
206 |
{ |
229 |
{ |
207 |
static char str[16]; |
230 |
time_t elapsed, eta; |
208 |
long elapsed, eta; |
|
|
209 |
off_t received, expected; |
231 |
off_t received, expected; |
210 |
|
232 |
|
211 |
elapsed = xs->last.tv_sec - xs->start.tv_sec; |
233 |
elapsed = xs->last.tv_sec - xs->start.tv_sec; |
212 |
received = xs->rcvd - xs->offset; |
234 |
received = xs->rcvd - xs->offset; |
213 |
expected = xs->size - xs->rcvd; |
235 |
expected = xs->size - xs->rcvd; |
214 |
eta = (long)((double)elapsed * expected / received); |
236 |
eta = (time_t)((double)elapsed * expected / received); |
215 |
if (eta > 3600) |
237 |
if (eta > 0) |
216 |
snprintf(str, sizeof str, "%02ldh%02ldm", |
238 |
stat_seconds(str, strsz, eta); |
217 |
eta / 3600, (eta % 3600) / 60); |
|
|
218 |
else if (eta > 0) |
219 |
snprintf(str, sizeof str, "%02ldm%02lds", |
220 |
eta / 60, eta % 60); |
221 |
else |
239 |
else |
222 |
snprintf(str, sizeof str, "%02ldm%02lds", |
240 |
stat_seconds(str, strsz, elapsed); |
223 |
elapsed / 60, elapsed % 60); |
|
|
224 |
return (str); |
225 |
} |
241 |
} |
226 |
|
242 |
|
227 |
/* |
243 |
/* |
Lines 228-237
struct xferstat {
Link Here
|
228 |
* Format a number as "xxxx YB" where Y is ' ', 'k', 'M'... |
244 |
* Format a number as "xxxx YB" where Y is ' ', 'k', 'M'... |
229 |
*/ |
245 |
*/ |
230 |
static const char *prefixes = " kMGTP"; |
246 |
static const char *prefixes = " kMGTP"; |
231 |
static const char * |
247 |
static void |
232 |
stat_bytes(off_t bytes) |
248 |
stat_bytes(char *str, size_t strsz, off_t bytes) |
233 |
{ |
249 |
{ |
234 |
static char str[16]; |
|
|
235 |
const char *prefix = prefixes; |
250 |
const char *prefix = prefixes; |
236 |
|
251 |
|
237 |
while (bytes > 9999 && prefix[1] != '\0') { |
252 |
while (bytes > 9999 && prefix[1] != '\0') { |
Lines 238-266
static const char *prefixes = " kMGTP";
Link Here
|
238 |
bytes /= 1024; |
253 |
bytes /= 1024; |
239 |
prefix++; |
254 |
prefix++; |
240 |
} |
255 |
} |
241 |
snprintf(str, sizeof str, "%4jd %cB", (intmax_t)bytes, *prefix); |
256 |
snprintf(str, strsz, "%4ju %cB", (uintmax_t)bytes, *prefix); |
242 |
return (str); |
|
|
243 |
} |
257 |
} |
244 |
|
258 |
|
245 |
/* |
259 |
/* |
246 |
* Compute and display transfer rate |
260 |
* Compute and display transfer rate |
247 |
*/ |
261 |
*/ |
248 |
static const char * |
262 |
static void |
249 |
stat_bps(struct xferstat *xs) |
263 |
stat_bps(char *str, size_t strsz, struct xferstat *xs) |
250 |
{ |
264 |
{ |
251 |
static char str[16]; |
265 |
char bytes[16]; |
252 |
double delta, bps; |
266 |
double delta, bps; |
253 |
|
267 |
|
254 |
delta = (xs->last.tv_sec + (xs->last.tv_usec / 1.e6)) |
268 |
delta = ((double)xs->last.tv_sec + (xs->last.tv_usec / 1.e6)) |
255 |
- (xs->last2.tv_sec + (xs->last2.tv_usec / 1.e6)); |
269 |
- ((double)xs->last2.tv_sec + (xs->last2.tv_usec / 1.e6)); |
256 |
|
270 |
|
257 |
if (delta == 0.0) { |
271 |
if (delta == 0.0) { |
258 |
snprintf(str, sizeof str, "?? Bps"); |
272 |
snprintf(str, strsz, "?? Bps"); |
259 |
} else { |
273 |
} else { |
260 |
bps = (xs->rcvd - xs->lastrcvd) / delta; |
274 |
bps = (xs->rcvd - xs->lastrcvd) / delta; |
261 |
snprintf(str, sizeof str, "%sps", stat_bytes((off_t)bps)); |
275 |
stat_bytes(bytes, sizeof bytes, (off_t)bps); |
|
|
276 |
snprintf(str, strsz, "%sps", bytes); |
262 |
} |
277 |
} |
263 |
return (str); |
|
|
264 |
} |
278 |
} |
265 |
|
279 |
|
266 |
/* |
280 |
/* |
Lines 269-279
static const char *prefixes = " kMGTP";
Link Here
|
269 |
static void |
283 |
static void |
270 |
stat_display(struct xferstat *xs, int force) |
284 |
stat_display(struct xferstat *xs, int force) |
271 |
{ |
285 |
{ |
|
|
286 |
char bytes[16], bps[16], eta[16]; |
272 |
struct timeval now; |
287 |
struct timeval now; |
273 |
int ctty_pgrp; |
288 |
int ctty_pgrp; |
274 |
|
289 |
|
275 |
/* check if we're the foreground process */ |
290 |
/* check if we're the foreground process */ |
276 |
if (ioctl(STDERR_FILENO, TIOCGPGRP, &ctty_pgrp) == -1 || |
291 |
if (ioctl(STDERR_FILENO, TIOCGPGRP, &ctty_pgrp) != 0 || |
277 |
(pid_t)ctty_pgrp != pgrp) |
292 |
(pid_t)ctty_pgrp != pgrp) |
278 |
return; |
293 |
return; |
279 |
|
294 |
|
Lines 284-309
stat_display(struct xferstat *xs, int force)
Link Here
|
284 |
xs->last = now; |
299 |
xs->last = now; |
285 |
|
300 |
|
286 |
fprintf(stderr, "\r%-46.46s", xs->name); |
301 |
fprintf(stderr, "\r%-46.46s", xs->name); |
287 |
if (xs->size <= 0) { |
302 |
if (xs->rcvd >= xs->size) { |
288 |
setproctitle("%s [%s]", xs->name, stat_bytes(xs->rcvd)); |
303 |
stat_bytes(bytes, sizeof bytes, xs->rcvd); |
289 |
fprintf(stderr, " %s", stat_bytes(xs->rcvd)); |
304 |
setproctitle("%s [%s]", xs->name, bytes); |
|
|
305 |
fprintf(stderr, " %s", bytes); |
290 |
} else { |
306 |
} else { |
|
|
307 |
stat_bytes(bytes, sizeof bytes, xs->size); |
291 |
setproctitle("%s [%d%% of %s]", xs->name, |
308 |
setproctitle("%s [%d%% of %s]", xs->name, |
292 |
(int)((100.0 * xs->rcvd) / xs->size), |
309 |
(int)((100.0 * xs->rcvd) / xs->size), |
293 |
stat_bytes(xs->size)); |
310 |
bytes); |
294 |
fprintf(stderr, "%3d%% of %s", |
311 |
fprintf(stderr, "%3d%% of %s", |
295 |
(int)((100.0 * xs->rcvd) / xs->size), |
312 |
(int)((100.0 * xs->rcvd) / xs->size), |
296 |
stat_bytes(xs->size)); |
313 |
bytes); |
297 |
} |
314 |
} |
298 |
if (force == 2) { |
315 |
if (force == 2) { |
299 |
xs->lastrcvd = xs->offset; |
316 |
xs->lastrcvd = xs->offset; |
300 |
xs->last2 = xs->start; |
317 |
xs->last2 = xs->start; |
301 |
} |
318 |
} |
302 |
fprintf(stderr, " %s", stat_bps(xs)); |
319 |
stat_bps(bps, sizeof bps, xs); |
|
|
320 |
fprintf(stderr, " %s", bps); |
303 |
if ((xs->size > 0 && xs->rcvd > 0 && |
321 |
if ((xs->size > 0 && xs->rcvd > 0 && |
304 |
xs->last.tv_sec >= xs->start.tv_sec + 3) || |
322 |
xs->last.tv_sec >= xs->start.tv_sec + 3) || |
305 |
force == 2) |
323 |
force == 2) { |
306 |
fprintf(stderr, " %s", stat_eta(xs)); |
324 |
stat_eta(eta, sizeof eta, xs); |
|
|
325 |
fprintf(stderr, " %s", eta); |
326 |
} |
307 |
xs->lastrcvd = xs->rcvd; |
327 |
xs->lastrcvd = xs->rcvd; |
308 |
} |
328 |
} |
309 |
|
329 |
|
Lines 313-326
stat_display(struct xferstat *xs, int force)
Link Here
|
313 |
static void |
333 |
static void |
314 |
stat_start(struct xferstat *xs, const char *name, off_t size, off_t offset) |
334 |
stat_start(struct xferstat *xs, const char *name, off_t size, off_t offset) |
315 |
{ |
335 |
{ |
|
|
336 |
|
337 |
memset(xs, 0, sizeof *xs); |
316 |
snprintf(xs->name, sizeof xs->name, "%s", name); |
338 |
snprintf(xs->name, sizeof xs->name, "%s", name); |
317 |
gettimeofday(&xs->start, NULL); |
339 |
gettimeofday(&xs->start, NULL); |
318 |
xs->last.tv_sec = xs->last.tv_usec = 0; |
340 |
xs->last2 = xs->last = xs->start; |
319 |
xs->size = size; |
341 |
xs->size = size; |
320 |
xs->offset = offset; |
342 |
xs->offset = offset; |
321 |
xs->rcvd = offset; |
343 |
xs->rcvd = offset; |
322 |
xs->lastrcvd = offset; |
344 |
xs->lastrcvd = offset; |
323 |
if (v_tty && v_level > 0) |
345 |
if (v_progress) |
324 |
stat_display(xs, 1); |
346 |
stat_display(xs, 1); |
325 |
else if (v_level > 0) |
347 |
else if (v_level > 0) |
326 |
fprintf(stderr, "%-46s", xs->name); |
348 |
fprintf(stderr, "%-46s", xs->name); |
Lines 332-339
stat_start(struct xferstat *xs, const char *name,
Link Here
|
332 |
static void |
354 |
static void |
333 |
stat_update(struct xferstat *xs, off_t rcvd) |
355 |
stat_update(struct xferstat *xs, off_t rcvd) |
334 |
{ |
356 |
{ |
|
|
357 |
|
335 |
xs->rcvd = rcvd; |
358 |
xs->rcvd = rcvd; |
336 |
if (v_tty && v_level > 0) |
359 |
if (v_progress) |
337 |
stat_display(xs, 0); |
360 |
stat_display(xs, 0); |
338 |
} |
361 |
} |
339 |
|
362 |
|
Lines 343-355
stat_update(struct xferstat *xs, off_t rcvd)
Link Here
|
343 |
static void |
366 |
static void |
344 |
stat_end(struct xferstat *xs) |
367 |
stat_end(struct xferstat *xs) |
345 |
{ |
368 |
{ |
|
|
369 |
char bytes[16], bps[16], eta[16]; |
370 |
|
346 |
gettimeofday(&xs->last, NULL); |
371 |
gettimeofday(&xs->last, NULL); |
347 |
if (v_tty && v_level > 0) { |
372 |
if (v_progress) { |
348 |
stat_display(xs, 2); |
373 |
stat_display(xs, 2); |
349 |
putc('\n', stderr); |
374 |
putc('\n', stderr); |
350 |
} else if (v_level > 0) { |
375 |
} else if (v_level > 0) { |
351 |
fprintf(stderr, " %s %s\n", |
376 |
stat_bytes(bytes, sizeof bytes, xs->size); |
352 |
stat_bytes(xs->size), stat_bps(xs)); |
377 |
stat_bps(bps, sizeof bps, xs); |
|
|
378 |
stat_eta(eta, sizeof eta, xs); |
379 |
fprintf(stderr, " %s %s %s\n", bytes, bps, eta); |
353 |
} |
380 |
} |
354 |
} |
381 |
} |
355 |
|
382 |
|
Lines 1110-1116
main(int argc, char *argv[])
Link Here
|
1110 |
|
1137 |
|
1111 |
/* check if output is to a tty (for progress report) */ |
1138 |
/* check if output is to a tty (for progress report) */ |
1112 |
v_tty = isatty(STDERR_FILENO); |
1139 |
v_tty = isatty(STDERR_FILENO); |
1113 |
if (v_tty) |
1140 |
v_progress = v_tty && v_level > 0; |
|
|
1141 |
if (v_progress) |
1114 |
pgrp = getpgrp(); |
1142 |
pgrp = getpgrp(); |
1115 |
|
1143 |
|
1116 |
r = 0; |
1144 |
r = 0; |