1 /* guestfish - the filesystem interactive shell
2 * Copyright (C) 2010 Red Hat Inc.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
32 /* Include these last since they redefine symbols such as 'lines'
33 * which seriously breaks other headers.
38 /* Provided by termcap or terminfo emulation, but not defined
41 extern const char *UP;
46 /* Choice of unicode spinners.
48 * For basic dingbats, see:
49 * http://www.fileformat.info/info/unicode/block/geometric_shapes/utf8test.htm
50 * http://www.fileformat.info/info/unicode/block/dingbats/utf8test.htm
52 * Arrows are a mess in unicode. This page helps a lot:
53 * http://xahlee.org/comp/unicode_arrows.html
55 * I prefer something which doesn't point, just spins.
57 /* Black pointing triangle. */
58 //static const char *us[] = { "\u25b2", "\u25b6", "\u25bc", "\u25c0" };
59 /* White pointing triangle. */
60 //static const char *us[] = { "\u25b3", "\u25b7", "\u25bd", "\u25c1" };
61 /* Circle with half black. */
62 static const char *us[] = { "\u25d0", "\u25d3", "\u25d1", "\u25d2" };
63 /* White square white quadrant. */
64 //static const char *us[] = { "\u25f0", "\u25f3", "\u25f2", "\u25f1" };
65 /* White circle white quadrant. */
66 //static const char *us[] = { "\u25f4", "\u25f7", "\u25f6", "\u25f5" };
68 //static const char *us[] = { "\u25e2", "\u25e3", "\u25e4", "\u25e5" };
69 /* Spinning arrow in 8 directions. */
70 //static const char *us[] = { "\u2190", "\u2196", "\u2191", "\u2197",
71 // "\u2192", "\u2198", "\u2193", "\u2199" };
74 static const char *as[] = { "/", "-", "\\", "|" };
81 n = sizeof us / sizeof us[0];
85 n = sizeof as / sizeof as[0];
91 static double start; /* start time of command */
92 static int count; /* number of progress notifications per cmd */
93 static struct rmsd rmsd; /* running mean and standard deviation */
95 /* This function is called just before we issue any command. */
97 reset_progress_bar (void)
99 /* The time at which this command was issued. */
100 struct timeval start_t;
101 gettimeofday (&start_t, NULL);
103 start = start_t.tv_sec + start_t.tv_usec / 1000000.;
110 /* Return remaining time estimate (in seconds) for current call.
112 * This returns the running mean estimate of remaining time, but if
113 * the latest estimate of total time is greater than two s.d.'s from
114 * the running mean then we don't print anything because we're not
115 * confident that the estimate is meaningful. (Returned value is <0.0
116 * when nothing should be printed).
119 estimate_remaining_time (double ratio)
124 struct timeval now_t;
125 gettimeofday (&now_t, NULL);
127 double now = now_t.tv_sec + now_t.tv_usec / 1000000.;
128 /* We've done 'ratio' of the work in 'now - start' seconds. */
129 double time_passed = now - start;
131 double total_time = time_passed / ratio;
133 /* Add total_time to running mean and s.d. and then see if our
134 * estimate of total time is meaningful.
136 rmsd_add_sample (&rmsd, total_time);
138 double mean = rmsd_get_mean (&rmsd);
139 double sd = rmsd_get_standard_deviation (&rmsd);
140 if (fabs (total_time - mean) >= 2.0*sd)
143 /* Don't return early estimates. */
144 if (time_passed < 3.0)
147 return total_time - time_passed;
150 /* The overhead is how much we subtract before we get to the progress
153 * / 100% [########---------------] xx:xx
155 * | | | | time (5 cols)
157 * | | open paren + close paren + space (3 cols)
159 * | percentage and space (5 cols)
161 * spinner and space (2 cols)
163 * Total = 2 + 5 + 3 + 5 = 15
165 #define COLS_OVERHEAD 15
167 /* Callback which displays a progress bar. */
169 progress_callback (guestfs_h *g, void *data,
170 uint64_t event, int event_handle, int flags,
171 const char *buf, size_t buf_len,
172 const uint64_t *array, size_t array_len)
177 /*uint64_t proc_nr = array[0];*/
178 /*uint64_t serial = array[1];*/
179 uint64_t position = array[2];
180 uint64_t total = array[3];
182 if (have_terminfo == 0) {
184 printf ("%" PRIu64 "/%" PRIu64 "\n", position, total);
186 int cols = tgetnum ((char *) "co");
187 if (cols < 32) goto dumb;
189 /* Update an existing progress bar just printed? */
191 tputs (UP, 2, putchar);
194 double ratio = (double) position / total;
195 if (ratio < 0) ratio = 0; else if (ratio > 1) ratio = 1;
198 int percent = 100.0 * ratio;
199 printf ("%s%3d%% ", spinner (count), percent);
201 fputs (" 100% ", stdout);
204 int dots = ratio * (double) (cols - COLS_OVERHEAD);
206 const char *s_open, *s_dot, *s_dash, *s_close;
208 s_open = "\u27e6"; s_dot = "\u2589"; s_dash = "\u2550"; s_close = "\u27e7";
210 s_open = "["; s_dot = "#"; s_dash = "-"; s_close = "]";
213 fputs (s_open, stdout);
215 for (i = 0; i < dots; ++i)
216 fputs (s_dot, stdout);
217 for (i = dots; i < cols - COLS_OVERHEAD; ++i)
218 fputs (s_dash, stdout);
219 fputs (s_close, stdout);
223 double estimate = estimate_remaining_time (ratio);
224 if (estimate >= 100.0 * 60.0 * 60.0 /* >= 100 hours */) {
225 /* Display hours<h> */
226 estimate /= 60. * 60.;
227 int hh = floor (estimate);
229 } else if (estimate >= 100.0 * 60.0 /* >= 100 minutes */) {
230 /* Display hours<h>minutes */
231 estimate /= 60. * 60.;
232 int hh = floor (estimate);
234 int mm = floor (modf (estimate, &ignore) * 60.);
235 printf ("%02dh%02d", hh, mm);
236 } else if (estimate >= 0.0) {
237 /* Display minutes:seconds */
239 int mm = floor (estimate);
241 int ss = floor (modf (estimate, &ignore) * 60.);
242 printf ("%02d:%02d", mm, ss);
244 else /* < 0 means estimate was not meaningful */
245 fputs ("--:--", stdout);
247 fputc ('\n', stdout);