| /* progress.c - show loading progress */ |
| /* |
| * GRUB -- GRand Unified Bootloader |
| * Copyright (C) 2013 Free Software Foundation, Inc. |
| * |
| * GRUB is free software: you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation, either version 3 of the License, or |
| * (at your option) any later version. |
| * |
| * GRUB is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with GRUB. If not, see <http://www.gnu.org/licenses/>. |
| */ |
| |
| #include <grub/types.h> |
| #include <grub/time.h> |
| #include <grub/term.h> |
| #include <grub/dl.h> |
| #include <grub/misc.h> |
| #include <grub/normal.h> |
| #include <grub/net.h> |
| |
| GRUB_MOD_LICENSE ("GPLv3+"); |
| |
| #define UPDATE_INTERVAL 800 |
| |
| static void |
| grub_file_progress_hook_real (grub_disk_addr_t sector __attribute__ ((unused)), |
| unsigned offset __attribute__ ((unused)), |
| unsigned length, void *data) |
| { |
| static int call_depth = 0; |
| grub_uint64_t now; |
| static grub_uint64_t last_progress_update_time; |
| grub_file_t file = data; |
| const char *e; |
| file->progress_offset += length; |
| |
| if (call_depth) |
| return; |
| |
| e = grub_env_get ("enable_progress_indicator"); |
| if (e && e[0] == '0') { |
| return; |
| } |
| |
| call_depth = 1; |
| now = grub_get_time_ms (); |
| |
| if (((now - last_progress_update_time > UPDATE_INTERVAL) && |
| (file->progress_offset - file->offset > 0)) || |
| (file->progress_offset == file->size)) |
| { |
| static char buffer[80]; |
| struct grub_term_output *term; |
| const char *partial_file_name; |
| |
| unsigned long long percent; |
| grub_uint64_t current_speed; |
| |
| if (now - file->last_progress_time < 10) |
| current_speed = 0; |
| else |
| current_speed = grub_divmod64 ((file->progress_offset |
| - file->last_progress_offset) |
| * 100ULL * 1000ULL, |
| now - file->last_progress_time, 0); |
| |
| if (file->size == 0) |
| percent = 100; |
| else |
| percent = grub_divmod64 (100 * file->progress_offset, |
| file->size, 0); |
| |
| /* grub_net_fs_open() saves off partial file structure before name is initialized. |
| It already saves passed file name in net structure so just use it in this case. |
| */ |
| if (file->device->net) |
| partial_file_name = grub_strrchr (file->device->net->name, '/'); |
| else if (file->name) /* grub_file_open() may leave it as NULL */ |
| partial_file_name = grub_strrchr (file->name, '/'); |
| else |
| partial_file_name = NULL; |
| if (partial_file_name) |
| partial_file_name++; |
| else |
| partial_file_name = ""; |
| |
| file->estimated_speed = (file->estimated_speed + current_speed) >> 1; |
| |
| grub_snprintf (buffer, sizeof (buffer), " [ %.20s %s %llu%% ", |
| partial_file_name, |
| grub_get_human_size (file->progress_offset, |
| GRUB_HUMAN_SIZE_NORMAL), |
| (unsigned long long) percent); |
| |
| char *ptr = buffer + grub_strlen (buffer); |
| grub_snprintf (ptr, sizeof (buffer) - (ptr - buffer), "%s ]", |
| grub_get_human_size (file->estimated_speed, |
| GRUB_HUMAN_SIZE_SPEED)); |
| |
| grub_size_t len = grub_strlen (buffer); |
| FOR_ACTIVE_TERM_OUTPUTS (term) |
| { |
| if (term->progress_update_counter++ > term->progress_update_divisor |
| || (file->progress_offset == file->size |
| && term->progress_update_divisor |
| != (unsigned) GRUB_PROGRESS_NO_UPDATE)) |
| { |
| struct grub_term_coordinate old_pos = grub_term_getxy (term); |
| struct grub_term_coordinate new_pos = old_pos; |
| new_pos.x = grub_term_width (term) - len - 1; |
| |
| grub_term_gotoxy (term, new_pos); |
| grub_puts_terminal (buffer, term); |
| grub_term_gotoxy (term, old_pos); |
| |
| term->progress_update_counter = 0; |
| |
| if (term->refresh) |
| term->refresh (term); |
| } |
| } |
| |
| file->last_progress_offset = file->progress_offset; |
| file->last_progress_time = now; |
| last_progress_update_time = now; |
| } |
| call_depth = 0; |
| } |
| |
| GRUB_MOD_INIT(progress) |
| { |
| grub_file_progress_hook = grub_file_progress_hook_real; |
| } |
| |
| GRUB_MOD_FINI(progress) |
| { |
| grub_file_progress_hook = 0; |
| } |