113498266Sopenharmony_ci/*************************************************************************** 213498266Sopenharmony_ci * _ _ ____ _ 313498266Sopenharmony_ci * Project ___| | | | _ \| | 413498266Sopenharmony_ci * / __| | | | |_) | | 513498266Sopenharmony_ci * | (__| |_| | _ <| |___ 613498266Sopenharmony_ci * \___|\___/|_| \_\_____| 713498266Sopenharmony_ci * 813498266Sopenharmony_ci * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 913498266Sopenharmony_ci * 1013498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which 1113498266Sopenharmony_ci * you should have received as part of this distribution. The terms 1213498266Sopenharmony_ci * are also available at https://curl.se/docs/copyright.html. 1313498266Sopenharmony_ci * 1413498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell 1513498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is 1613498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file. 1713498266Sopenharmony_ci * 1813498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 1913498266Sopenharmony_ci * KIND, either express or implied. 2013498266Sopenharmony_ci * 2113498266Sopenharmony_ci * SPDX-License-Identifier: curl 2213498266Sopenharmony_ci * 2313498266Sopenharmony_ci ***************************************************************************/ 2413498266Sopenharmony_ci#include "tool_setup.h" 2513498266Sopenharmony_ci#include "tool_operate.h" 2613498266Sopenharmony_ci#include "tool_progress.h" 2713498266Sopenharmony_ci#include "tool_util.h" 2813498266Sopenharmony_ci 2913498266Sopenharmony_ci#define ENABLE_CURLX_PRINTF 3013498266Sopenharmony_ci/* use our own printf() functions */ 3113498266Sopenharmony_ci#include "curlx.h" 3213498266Sopenharmony_ci 3313498266Sopenharmony_ci/* The point of this function would be to return a string of the input data, 3413498266Sopenharmony_ci but never longer than 5 columns (+ one zero byte). 3513498266Sopenharmony_ci Add suffix k, M, G when suitable... */ 3613498266Sopenharmony_cistatic char *max5data(curl_off_t bytes, char *max5) 3713498266Sopenharmony_ci{ 3813498266Sopenharmony_ci#define ONE_KILOBYTE CURL_OFF_T_C(1024) 3913498266Sopenharmony_ci#define ONE_MEGABYTE (CURL_OFF_T_C(1024) * ONE_KILOBYTE) 4013498266Sopenharmony_ci#define ONE_GIGABYTE (CURL_OFF_T_C(1024) * ONE_MEGABYTE) 4113498266Sopenharmony_ci#define ONE_TERABYTE (CURL_OFF_T_C(1024) * ONE_GIGABYTE) 4213498266Sopenharmony_ci#define ONE_PETABYTE (CURL_OFF_T_C(1024) * ONE_TERABYTE) 4313498266Sopenharmony_ci 4413498266Sopenharmony_ci if(bytes < CURL_OFF_T_C(100000)) 4513498266Sopenharmony_ci msnprintf(max5, 6, "%5" CURL_FORMAT_CURL_OFF_T, bytes); 4613498266Sopenharmony_ci 4713498266Sopenharmony_ci else if(bytes < CURL_OFF_T_C(10000) * ONE_KILOBYTE) 4813498266Sopenharmony_ci msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "k", bytes/ONE_KILOBYTE); 4913498266Sopenharmony_ci 5013498266Sopenharmony_ci else if(bytes < CURL_OFF_T_C(100) * ONE_MEGABYTE) 5113498266Sopenharmony_ci /* 'XX.XM' is good as long as we're less than 100 megs */ 5213498266Sopenharmony_ci msnprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0" 5313498266Sopenharmony_ci CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE, 5413498266Sopenharmony_ci (bytes%ONE_MEGABYTE) / (ONE_MEGABYTE/CURL_OFF_T_C(10)) ); 5513498266Sopenharmony_ci 5613498266Sopenharmony_ci else if(bytes < CURL_OFF_T_C(10000) * ONE_MEGABYTE) 5713498266Sopenharmony_ci /* 'XXXXM' is good until we're at 10000MB or above */ 5813498266Sopenharmony_ci msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE); 5913498266Sopenharmony_ci 6013498266Sopenharmony_ci else if(bytes < CURL_OFF_T_C(100) * ONE_GIGABYTE) 6113498266Sopenharmony_ci /* 10000 MB - 100 GB, we show it as XX.XG */ 6213498266Sopenharmony_ci msnprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0" 6313498266Sopenharmony_ci CURL_FORMAT_CURL_OFF_T "G", bytes/ONE_GIGABYTE, 6413498266Sopenharmony_ci (bytes%ONE_GIGABYTE) / (ONE_GIGABYTE/CURL_OFF_T_C(10)) ); 6513498266Sopenharmony_ci 6613498266Sopenharmony_ci else if(bytes < CURL_OFF_T_C(10000) * ONE_GIGABYTE) 6713498266Sopenharmony_ci /* up to 10000GB, display without decimal: XXXXG */ 6813498266Sopenharmony_ci msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "G", bytes/ONE_GIGABYTE); 6913498266Sopenharmony_ci 7013498266Sopenharmony_ci else if(bytes < CURL_OFF_T_C(10000) * ONE_TERABYTE) 7113498266Sopenharmony_ci /* up to 10000TB, display without decimal: XXXXT */ 7213498266Sopenharmony_ci msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "T", bytes/ONE_TERABYTE); 7313498266Sopenharmony_ci 7413498266Sopenharmony_ci else 7513498266Sopenharmony_ci /* up to 10000PB, display without decimal: XXXXP */ 7613498266Sopenharmony_ci msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "P", bytes/ONE_PETABYTE); 7713498266Sopenharmony_ci 7813498266Sopenharmony_ci /* 16384 petabytes (16 exabytes) is the maximum a 64 bit unsigned number can 7913498266Sopenharmony_ci hold, but our data type is signed so 8192PB will be the maximum. */ 8013498266Sopenharmony_ci return max5; 8113498266Sopenharmony_ci} 8213498266Sopenharmony_ci 8313498266Sopenharmony_ciint xferinfo_cb(void *clientp, 8413498266Sopenharmony_ci curl_off_t dltotal, 8513498266Sopenharmony_ci curl_off_t dlnow, 8613498266Sopenharmony_ci curl_off_t ultotal, 8713498266Sopenharmony_ci curl_off_t ulnow) 8813498266Sopenharmony_ci{ 8913498266Sopenharmony_ci struct per_transfer *per = clientp; 9013498266Sopenharmony_ci struct OperationConfig *config = per->config; 9113498266Sopenharmony_ci per->dltotal = dltotal; 9213498266Sopenharmony_ci per->dlnow = dlnow; 9313498266Sopenharmony_ci per->ultotal = ultotal; 9413498266Sopenharmony_ci per->ulnow = ulnow; 9513498266Sopenharmony_ci 9613498266Sopenharmony_ci if(per->abort) 9713498266Sopenharmony_ci return 1; 9813498266Sopenharmony_ci 9913498266Sopenharmony_ci if(config->readbusy) { 10013498266Sopenharmony_ci config->readbusy = FALSE; 10113498266Sopenharmony_ci curl_easy_pause(per->curl, CURLPAUSE_CONT); 10213498266Sopenharmony_ci } 10313498266Sopenharmony_ci 10413498266Sopenharmony_ci return 0; 10513498266Sopenharmony_ci} 10613498266Sopenharmony_ci 10713498266Sopenharmony_ci/* Provide a string that is 2 + 1 + 2 + 1 + 2 = 8 letters long (plus the zero 10813498266Sopenharmony_ci byte) */ 10913498266Sopenharmony_cistatic void time2str(char *r, curl_off_t seconds) 11013498266Sopenharmony_ci{ 11113498266Sopenharmony_ci curl_off_t h; 11213498266Sopenharmony_ci if(seconds <= 0) { 11313498266Sopenharmony_ci strcpy(r, "--:--:--"); 11413498266Sopenharmony_ci return; 11513498266Sopenharmony_ci } 11613498266Sopenharmony_ci h = seconds / CURL_OFF_T_C(3600); 11713498266Sopenharmony_ci if(h <= CURL_OFF_T_C(99)) { 11813498266Sopenharmony_ci curl_off_t m = (seconds - (h*CURL_OFF_T_C(3600))) / CURL_OFF_T_C(60); 11913498266Sopenharmony_ci curl_off_t s = (seconds - (h*CURL_OFF_T_C(3600))) - (m*CURL_OFF_T_C(60)); 12013498266Sopenharmony_ci msnprintf(r, 9, "%2" CURL_FORMAT_CURL_OFF_T ":%02" CURL_FORMAT_CURL_OFF_T 12113498266Sopenharmony_ci ":%02" CURL_FORMAT_CURL_OFF_T, h, m, s); 12213498266Sopenharmony_ci } 12313498266Sopenharmony_ci else { 12413498266Sopenharmony_ci /* this equals to more than 99 hours, switch to a more suitable output 12513498266Sopenharmony_ci format to fit within the limits. */ 12613498266Sopenharmony_ci curl_off_t d = seconds / CURL_OFF_T_C(86400); 12713498266Sopenharmony_ci h = (seconds - (d*CURL_OFF_T_C(86400))) / CURL_OFF_T_C(3600); 12813498266Sopenharmony_ci if(d <= CURL_OFF_T_C(999)) 12913498266Sopenharmony_ci msnprintf(r, 9, "%3" CURL_FORMAT_CURL_OFF_T 13013498266Sopenharmony_ci "d %02" CURL_FORMAT_CURL_OFF_T "h", d, h); 13113498266Sopenharmony_ci else 13213498266Sopenharmony_ci msnprintf(r, 9, "%7" CURL_FORMAT_CURL_OFF_T "d", d); 13313498266Sopenharmony_ci } 13413498266Sopenharmony_ci} 13513498266Sopenharmony_ci 13613498266Sopenharmony_cistatic curl_off_t all_dltotal = 0; 13713498266Sopenharmony_cistatic curl_off_t all_ultotal = 0; 13813498266Sopenharmony_cistatic curl_off_t all_dlalready = 0; 13913498266Sopenharmony_cistatic curl_off_t all_ulalready = 0; 14013498266Sopenharmony_ci 14113498266Sopenharmony_cicurl_off_t all_xfers = 0; /* current total */ 14213498266Sopenharmony_ci 14313498266Sopenharmony_cistruct speedcount { 14413498266Sopenharmony_ci curl_off_t dl; 14513498266Sopenharmony_ci curl_off_t ul; 14613498266Sopenharmony_ci struct timeval stamp; 14713498266Sopenharmony_ci}; 14813498266Sopenharmony_ci#define SPEEDCNT 10 14913498266Sopenharmony_cistatic unsigned int speedindex; 15013498266Sopenharmony_cistatic bool indexwrapped; 15113498266Sopenharmony_cistatic struct speedcount speedstore[SPEEDCNT]; 15213498266Sopenharmony_ci 15313498266Sopenharmony_ci/* 15413498266Sopenharmony_ci |DL% UL% Dled Uled Xfers Live Total Current Left Speed 15513498266Sopenharmony_ci | 6 -- 9.9G 0 2 2 0:00:40 0:00:02 0:00:37 4087M 15613498266Sopenharmony_ci*/ 15713498266Sopenharmony_cibool progress_meter(struct GlobalConfig *global, 15813498266Sopenharmony_ci struct timeval *start, 15913498266Sopenharmony_ci bool final) 16013498266Sopenharmony_ci{ 16113498266Sopenharmony_ci static struct timeval stamp; 16213498266Sopenharmony_ci static bool header = FALSE; 16313498266Sopenharmony_ci struct timeval now; 16413498266Sopenharmony_ci long diff; 16513498266Sopenharmony_ci 16613498266Sopenharmony_ci if(global->noprogress || global->silent) 16713498266Sopenharmony_ci return FALSE; 16813498266Sopenharmony_ci 16913498266Sopenharmony_ci now = tvnow(); 17013498266Sopenharmony_ci diff = tvdiff(now, stamp); 17113498266Sopenharmony_ci 17213498266Sopenharmony_ci if(!header) { 17313498266Sopenharmony_ci header = TRUE; 17413498266Sopenharmony_ci fputs("DL% UL% Dled Uled Xfers Live " 17513498266Sopenharmony_ci "Total Current Left Speed\n", 17613498266Sopenharmony_ci tool_stderr); 17713498266Sopenharmony_ci } 17813498266Sopenharmony_ci if(final || (diff > 500)) { 17913498266Sopenharmony_ci char time_left[10]; 18013498266Sopenharmony_ci char time_total[10]; 18113498266Sopenharmony_ci char time_spent[10]; 18213498266Sopenharmony_ci char buffer[3][6]; 18313498266Sopenharmony_ci curl_off_t spent = tvdiff(now, *start)/1000; 18413498266Sopenharmony_ci char dlpercen[4]="--"; 18513498266Sopenharmony_ci char ulpercen[4]="--"; 18613498266Sopenharmony_ci struct per_transfer *per; 18713498266Sopenharmony_ci curl_off_t all_dlnow = 0; 18813498266Sopenharmony_ci curl_off_t all_ulnow = 0; 18913498266Sopenharmony_ci bool dlknown = TRUE; 19013498266Sopenharmony_ci bool ulknown = TRUE; 19113498266Sopenharmony_ci curl_off_t all_running = 0; /* in progress */ 19213498266Sopenharmony_ci curl_off_t speed = 0; 19313498266Sopenharmony_ci unsigned int i; 19413498266Sopenharmony_ci stamp = now; 19513498266Sopenharmony_ci 19613498266Sopenharmony_ci /* first add the amounts of the already completed transfers */ 19713498266Sopenharmony_ci all_dlnow += all_dlalready; 19813498266Sopenharmony_ci all_ulnow += all_ulalready; 19913498266Sopenharmony_ci 20013498266Sopenharmony_ci for(per = transfers; per; per = per->next) { 20113498266Sopenharmony_ci all_dlnow += per->dlnow; 20213498266Sopenharmony_ci all_ulnow += per->ulnow; 20313498266Sopenharmony_ci if(!per->dltotal) 20413498266Sopenharmony_ci dlknown = FALSE; 20513498266Sopenharmony_ci else if(!per->dltotal_added) { 20613498266Sopenharmony_ci /* only add this amount once */ 20713498266Sopenharmony_ci all_dltotal += per->dltotal; 20813498266Sopenharmony_ci per->dltotal_added = TRUE; 20913498266Sopenharmony_ci } 21013498266Sopenharmony_ci if(!per->ultotal) 21113498266Sopenharmony_ci ulknown = FALSE; 21213498266Sopenharmony_ci else if(!per->ultotal_added) { 21313498266Sopenharmony_ci /* only add this amount once */ 21413498266Sopenharmony_ci all_ultotal += per->ultotal; 21513498266Sopenharmony_ci per->ultotal_added = TRUE; 21613498266Sopenharmony_ci } 21713498266Sopenharmony_ci if(per->added) 21813498266Sopenharmony_ci all_running++; 21913498266Sopenharmony_ci } 22013498266Sopenharmony_ci if(dlknown && all_dltotal) 22113498266Sopenharmony_ci /* TODO: handle integer overflow */ 22213498266Sopenharmony_ci msnprintf(dlpercen, sizeof(dlpercen), "%3" CURL_FORMAT_CURL_OFF_T, 22313498266Sopenharmony_ci all_dlnow * 100 / all_dltotal); 22413498266Sopenharmony_ci if(ulknown && all_ultotal) 22513498266Sopenharmony_ci /* TODO: handle integer overflow */ 22613498266Sopenharmony_ci msnprintf(ulpercen, sizeof(ulpercen), "%3" CURL_FORMAT_CURL_OFF_T, 22713498266Sopenharmony_ci all_ulnow * 100 / all_ultotal); 22813498266Sopenharmony_ci 22913498266Sopenharmony_ci /* get the transfer speed, the higher of the two */ 23013498266Sopenharmony_ci 23113498266Sopenharmony_ci i = speedindex; 23213498266Sopenharmony_ci speedstore[i].dl = all_dlnow; 23313498266Sopenharmony_ci speedstore[i].ul = all_ulnow; 23413498266Sopenharmony_ci speedstore[i].stamp = now; 23513498266Sopenharmony_ci if(++speedindex >= SPEEDCNT) { 23613498266Sopenharmony_ci indexwrapped = TRUE; 23713498266Sopenharmony_ci speedindex = 0; 23813498266Sopenharmony_ci } 23913498266Sopenharmony_ci 24013498266Sopenharmony_ci { 24113498266Sopenharmony_ci long deltams; 24213498266Sopenharmony_ci curl_off_t dl; 24313498266Sopenharmony_ci curl_off_t ul; 24413498266Sopenharmony_ci curl_off_t dls; 24513498266Sopenharmony_ci curl_off_t uls; 24613498266Sopenharmony_ci if(indexwrapped) { 24713498266Sopenharmony_ci /* 'speedindex' is the oldest stored data */ 24813498266Sopenharmony_ci deltams = tvdiff(now, speedstore[speedindex].stamp); 24913498266Sopenharmony_ci dl = all_dlnow - speedstore[speedindex].dl; 25013498266Sopenharmony_ci ul = all_ulnow - speedstore[speedindex].ul; 25113498266Sopenharmony_ci } 25213498266Sopenharmony_ci else { 25313498266Sopenharmony_ci /* since the beginning */ 25413498266Sopenharmony_ci deltams = tvdiff(now, *start); 25513498266Sopenharmony_ci dl = all_dlnow; 25613498266Sopenharmony_ci ul = all_ulnow; 25713498266Sopenharmony_ci } 25813498266Sopenharmony_ci if(!deltams) /* no division by zero please */ 25913498266Sopenharmony_ci deltams++; 26013498266Sopenharmony_ci dls = (curl_off_t)((double)dl / ((double)deltams/1000.0)); 26113498266Sopenharmony_ci uls = (curl_off_t)((double)ul / ((double)deltams/1000.0)); 26213498266Sopenharmony_ci speed = dls > uls ? dls : uls; 26313498266Sopenharmony_ci } 26413498266Sopenharmony_ci 26513498266Sopenharmony_ci 26613498266Sopenharmony_ci if(dlknown && speed) { 26713498266Sopenharmony_ci curl_off_t est = all_dltotal / speed; 26813498266Sopenharmony_ci curl_off_t left = (all_dltotal - all_dlnow) / speed; 26913498266Sopenharmony_ci time2str(time_left, left); 27013498266Sopenharmony_ci time2str(time_total, est); 27113498266Sopenharmony_ci } 27213498266Sopenharmony_ci else { 27313498266Sopenharmony_ci time2str(time_left, 0); 27413498266Sopenharmony_ci time2str(time_total, 0); 27513498266Sopenharmony_ci } 27613498266Sopenharmony_ci time2str(time_spent, spent); 27713498266Sopenharmony_ci 27813498266Sopenharmony_ci fprintf(tool_stderr, 27913498266Sopenharmony_ci "\r" 28013498266Sopenharmony_ci "%-3s " /* percent downloaded */ 28113498266Sopenharmony_ci "%-3s " /* percent uploaded */ 28213498266Sopenharmony_ci "%s " /* Dled */ 28313498266Sopenharmony_ci "%s " /* Uled */ 28413498266Sopenharmony_ci "%5" CURL_FORMAT_CURL_OFF_T " " /* Xfers */ 28513498266Sopenharmony_ci "%5" CURL_FORMAT_CURL_OFF_T " " /* Live */ 28613498266Sopenharmony_ci " %s " /* Total time */ 28713498266Sopenharmony_ci "%s " /* Current time */ 28813498266Sopenharmony_ci "%s " /* Time left */ 28913498266Sopenharmony_ci "%s " /* Speed */ 29013498266Sopenharmony_ci "%5s" /* final newline */, 29113498266Sopenharmony_ci 29213498266Sopenharmony_ci dlpercen, /* 3 letters */ 29313498266Sopenharmony_ci ulpercen, /* 3 letters */ 29413498266Sopenharmony_ci max5data(all_dlnow, buffer[0]), 29513498266Sopenharmony_ci max5data(all_ulnow, buffer[1]), 29613498266Sopenharmony_ci all_xfers, 29713498266Sopenharmony_ci all_running, 29813498266Sopenharmony_ci time_total, 29913498266Sopenharmony_ci time_spent, 30013498266Sopenharmony_ci time_left, 30113498266Sopenharmony_ci max5data(speed, buffer[2]), /* speed */ 30213498266Sopenharmony_ci final ? "\n" :""); 30313498266Sopenharmony_ci return TRUE; 30413498266Sopenharmony_ci } 30513498266Sopenharmony_ci return FALSE; 30613498266Sopenharmony_ci} 30713498266Sopenharmony_ci 30813498266Sopenharmony_civoid progress_finalize(struct per_transfer *per) 30913498266Sopenharmony_ci{ 31013498266Sopenharmony_ci /* get the numbers before this transfer goes away */ 31113498266Sopenharmony_ci all_dlalready += per->dlnow; 31213498266Sopenharmony_ci all_ulalready += per->ulnow; 31313498266Sopenharmony_ci if(!per->dltotal_added) { 31413498266Sopenharmony_ci all_dltotal += per->dltotal; 31513498266Sopenharmony_ci per->dltotal_added = TRUE; 31613498266Sopenharmony_ci } 31713498266Sopenharmony_ci if(!per->ultotal_added) { 31813498266Sopenharmony_ci all_ultotal += per->ultotal; 31913498266Sopenharmony_ci per->ultotal_added = TRUE; 32013498266Sopenharmony_ci } 32113498266Sopenharmony_ci} 322