diff --git a/ChangeLog b/ChangeLog index a4a0a87ce..ba18817a4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,31 @@ +2013-10-22 Paulo Flabiano Smorigo + + Add new progress module that displays the load progress of files. + + * grub-core/lib/progress.c: New file. + * grub-core/Makefile.core.def (progress): New module. + * grub-core/kern/file.c (grub_file_open): File name added. + * (grub_file_read): Progress hook added. + * grub-core/fs/cbfs.c (grub_cbfs_read): Likewise. + * grub-core/fs/cpio_common.c (grub_cpio_read): Likewise. + * grub-core/net/net.c (grub_net_fs_read_real): Likewise. + * include/grub/file.h (struct grub_file): Add progress module members. + * include/grub/term.h (struct grub_term_output): Likewise. + * grub-core/osdep/unix/emuconsole.c (grub_console_term_output): + Terminal velocity added. + * grub-core/osdep/windows/emuconsole.c (grub_console_term_output): Likewise. + * grub-core/term/arc/console.c (grub_console_term_output): Likewise. + * grub-core/term/efi/console.c (grub_console_term_output): Likewise. + * grub-core/term/gfxterm.c (grub_video_term): Likewise. + * grub-core/term/i386/coreboot/cbmemc.c (grub_cbmemc_term_output): Likewise. + * grub-core/term/i386/pc/console.c (grub_console_term_output): Likewise. + * grub-core/term/i386/pc/vga_text.c (grub_vga_text_term): Likewise. + * grub-core/term/ieee1275/console.c (grub_console_term_output): Likewise. + * grub-core/term/morse.c (grub_audio_term_output): Likewise. + * grub-core/term/serial.c (grub_serial_term_output): Likewise. + * grub-core/term/spkmodem.c (grub_spkmodem_term_output): Likewise. + * grub-core/term/uboot/console.c (uboot_console_term_output): Likewise. + 2013-10-22 Vladimir Serbinenko Verify signatures of signatures unless --skip-sig is specified. diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index c8ce7c951..abd54bae4 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -2135,3 +2135,8 @@ module = { name = tr; common = commands/tr.c; }; + +module = { + name = progress; + common = lib/progress.c; +}; diff --git a/grub-core/fs/cbfs.c b/grub-core/fs/cbfs.c index 58a8427d5..c79ec433a 100644 --- a/grub-core/fs/cbfs.c +++ b/grub-core/fs/cbfs.c @@ -243,10 +243,17 @@ static grub_ssize_t grub_cbfs_read (grub_file_t file, char *buf, grub_size_t len) { struct grub_archelp_data *data; + grub_ssize_t ret; data = file->data; - return (grub_disk_read (data->disk, 0, data->dofs + file->offset, - len, buf)) ? -1 : (grub_ssize_t) len; + data->disk->read_hook = file->read_hook; + data->disk->read_hook_data = file->read_hook_data; + + ret = (grub_disk_read (data->disk, 0, data->dofs + file->offset, + len, buf)) ? -1 : (grub_ssize_t) len; + data->disk->read_hook = 0; + + return ret; } static grub_err_t diff --git a/grub-core/fs/cpio_common.c b/grub-core/fs/cpio_common.c index 370324ceb..b0ae9f445 100644 --- a/grub-core/fs/cpio_common.c +++ b/grub-core/fs/cpio_common.c @@ -200,10 +200,17 @@ static grub_ssize_t grub_cpio_read (grub_file_t file, char *buf, grub_size_t len) { struct grub_archelp_data *data; + grub_ssize_t ret; data = file->data; - return (grub_disk_read (data->disk, 0, data->dofs + file->offset, - len, buf)) ? -1 : (grub_ssize_t) len; + data->disk->read_hook = file->read_hook; + data->disk->read_hook_data = file->read_hook_data; + + ret = (grub_disk_read (data->disk, 0, data->dofs + file->offset, + len, buf)) ? -1 : (grub_ssize_t) len; + data->disk->read_hook = 0; + + return ret; } static grub_err_t diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c index 64266686d..ea1817a41 100644 --- a/grub-core/kern/file.c +++ b/grub-core/kern/file.c @@ -87,6 +87,9 @@ grub_file_open (const char *name) if (! file) goto fail; + file->name = grub_strdup (name); + grub_errno = GRUB_ERR_NONE; + file->device = device; if (device->disk && file_name[0] != '/') @@ -131,10 +134,14 @@ grub_file_open (const char *name) return 0; } +grub_disk_read_hook_t grub_file_progress_hook; + grub_ssize_t grub_file_read (grub_file_t file, void *buf, grub_size_t len) { grub_ssize_t res; + grub_disk_read_hook_t read_hook; + void *read_hook_data; if (file->offset > file->size) { @@ -155,7 +162,17 @@ grub_file_read (grub_file_t file, void *buf, grub_size_t len) if (len == 0) return 0; + read_hook = file->read_hook; + read_hook_data = file->read_hook_data; + if (!file->read_hook) + { + file->read_hook = grub_file_progress_hook; + file->read_hook_data = file; + file->progress_offset = file->offset; + } res = (file->fs->read) (file, buf, len); + file->read_hook = read_hook; + file->read_hook_data = read_hook_data; if (res > 0) file->offset += res; diff --git a/grub-core/lib/progress.c b/grub-core/lib/progress.c new file mode 100644 index 000000000..8b34c6a2d --- /dev/null +++ b/grub-core/lib/progress.c @@ -0,0 +1,100 @@ +/* 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 . + */ + +#include +#include +#include +#include +#include +#include + +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) +{ + grub_uint64_t now = grub_get_time_ms (); + static grub_uint64_t last_progress_update_time; + grub_file_t file = data; + file->progress_offset += length; + + if (((now - last_progress_update_time > UPDATE_INTERVAL) && + (file->progress_offset - file->offset > 0)) || + (file->progress_offset == file->size)) + { + char buffer[80]; + struct grub_term_output *term; + char *partial_file_name = grub_strrchr (file->name, '/') + 1; + + grub_uint64_t current_speed = grub_divmod64 ((file->progress_offset - + file->last_progress_offset) + * 100ULL * 1000ULL, + now - file->last_progress_time, 0); + + 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), + (100 * file->progress_offset) / file->size); + + 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_uint16_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; + } + } + + file->last_progress_offset = file->progress_offset; + file->last_progress_time = now; + last_progress_update_time = now; + } +} + +GRUB_MOD_INIT(progress) +{ + grub_file_progress_hook = grub_file_progress_hook_real; +} + +GRUB_MOD_FINI(progress) +{ + grub_file_progress_hook = 0; +} diff --git a/grub-core/net/net.c b/grub-core/net/net.c index da50cbffe..6d143fb51 100644 --- a/grub-core/net/net.c +++ b/grub-core/net/net.c @@ -1536,6 +1536,8 @@ grub_net_fs_read_real (grub_file_t file, char *buf, grub_size_t len) len -= amount; total += amount; file->device->net->offset += amount; + if (grub_file_progress_hook) + grub_file_progress_hook (0, 0, amount, file); if (buf) { grub_memcpy (ptr, nb->data, amount); diff --git a/grub-core/osdep/unix/emuconsole.c b/grub-core/osdep/unix/emuconsole.c index 53aa28500..9c1b5505b 100644 --- a/grub-core/osdep/unix/emuconsole.c +++ b/grub-core/osdep/unix/emuconsole.c @@ -149,6 +149,7 @@ static struct grub_term_output grub_console_term_output = .setcolorstate = grub_terminfo_setcolorstate, .setcursor = grub_terminfo_setcursor, .data = &grub_console_terminfo_output, + .progress_update_divisor = GRUB_PROGRESS_FAST }; void diff --git a/grub-core/osdep/windows/emuconsole.c b/grub-core/osdep/windows/emuconsole.c index f3414eff7..a2acf2637 100644 --- a/grub-core/osdep/windows/emuconsole.c +++ b/grub-core/osdep/windows/emuconsole.c @@ -283,7 +283,8 @@ static struct grub_term_output grub_console_term_output = .cls = grub_console_cls, .setcolorstate = grub_console_setcolorstate, .setcursor = grub_console_setcursor, - .flags = GRUB_TERM_CODE_TYPE_VISUAL_GLYPHS + .flags = GRUB_TERM_CODE_TYPE_VISUAL_GLYPHS, + .progress_update_divisor = GRUB_PROGRESS_FAST }; void diff --git a/grub-core/term/arc/console.c b/grub-core/term/arc/console.c index 87a65cc16..330a9f7ee 100644 --- a/grub-core/term/arc/console.c +++ b/grub-core/term/arc/console.c @@ -188,6 +188,7 @@ static struct grub_term_output grub_console_term_output = .setcursor = grub_terminfo_setcursor, .flags = GRUB_TERM_CODE_TYPE_ASCII, .data = &grub_console_terminfo_output, + .progress_update_divisor = GRUB_PROGRESS_FAST }; void diff --git a/grub-core/term/efi/console.c b/grub-core/term/efi/console.c index e6bb50d65..a000fa648 100644 --- a/grub-core/term/efi/console.c +++ b/grub-core/term/efi/console.c @@ -276,7 +276,8 @@ static struct grub_term_output grub_console_term_output = .cls = grub_console_cls, .setcolorstate = grub_console_setcolorstate, .setcursor = grub_console_setcursor, - .flags = GRUB_TERM_CODE_TYPE_VISUAL_GLYPHS + .flags = GRUB_TERM_CODE_TYPE_VISUAL_GLYPHS, + .progress_update_divisor = GRUB_PROGRESS_FAST }; void diff --git a/grub-core/term/gfxterm.c b/grub-core/term/gfxterm.c index 83b42cf50..ce0bce705 100644 --- a/grub-core/term/gfxterm.c +++ b/grub-core/term/gfxterm.c @@ -1108,6 +1108,7 @@ static struct grub_term_output grub_video_term = .refresh = grub_gfxterm_refresh, .fullscreen = grub_gfxterm_fullscreen, .flags = GRUB_TERM_CODE_TYPE_VISUAL_GLYPHS, + .progress_update_divisor = GRUB_PROGRESS_SLOW, .next = 0 }; diff --git a/grub-core/term/i386/coreboot/cbmemc.c b/grub-core/term/i386/coreboot/cbmemc.c index 2a0877ce0..25e64a05c 100644 --- a/grub-core/term/i386/coreboot/cbmemc.c +++ b/grub-core/term/i386/coreboot/cbmemc.c @@ -68,6 +68,7 @@ static struct grub_term_output grub_cbmemc_term_output = .setcursor = grub_terminfo_setcursor, .flags = GRUB_TERM_CODE_TYPE_ASCII, .data = &grub_cbmemc_terminfo_output, + .progress_update_divisor = GRUB_PROGRESS_NO_UPDATE }; static int diff --git a/grub-core/term/i386/pc/console.c b/grub-core/term/i386/pc/console.c index a727653d7..28de46b57 100644 --- a/grub-core/term/i386/pc/console.c +++ b/grub-core/term/i386/pc/console.c @@ -292,6 +292,7 @@ static struct grub_term_output grub_console_term_output = .setcolorstate = grub_console_setcolorstate, .setcursor = grub_console_setcursor, .flags = GRUB_TERM_CODE_TYPE_CP437, + .progress_update_divisor = GRUB_PROGRESS_FAST }; void diff --git a/grub-core/term/i386/pc/vga_text.c b/grub-core/term/i386/pc/vga_text.c index 33834bf74..1234e6100 100644 --- a/grub-core/term/i386/pc/vga_text.c +++ b/grub-core/term/i386/pc/vga_text.c @@ -267,6 +267,7 @@ static struct grub_term_output grub_vga_text_term = .setcolorstate = grub_vga_text_setcolorstate, .setcursor = grub_vga_text_setcursor, .flags = GRUB_TERM_CODE_TYPE_CP437, + .progress_update_divisor = GRUB_PROGRESS_FAST }; /* FIXME: this is was too spaghetti. */ diff --git a/grub-core/term/ieee1275/console.c b/grub-core/term/ieee1275/console.c index 17010e744..7e797a7d4 100644 --- a/grub-core/term/ieee1275/console.c +++ b/grub-core/term/ieee1275/console.c @@ -236,6 +236,7 @@ static struct grub_term_output grub_console_term_output = .setcursor = grub_console_setcursor, .flags = GRUB_TERM_CODE_TYPE_ASCII, .data = &grub_console_terminfo_output, + .progress_update_divisor = GRUB_PROGRESS_FAST }; void diff --git a/grub-core/term/morse.c b/grub-core/term/morse.c index ba84dfe14..13b8e863e 100644 --- a/grub-core/term/morse.c +++ b/grub-core/term/morse.c @@ -118,7 +118,8 @@ static struct grub_term_output grub_audio_term_output = .cls = (void *) dummy, .setcolorstate = (void *) dummy, .setcursor = (void *) dummy, - .flags = GRUB_TERM_CODE_TYPE_ASCII | GRUB_TERM_DUMB + .flags = GRUB_TERM_CODE_TYPE_ASCII | GRUB_TERM_DUMB, + .progress_update_divisor = GRUB_PROGRESS_NO_UPDATE }; GRUB_MOD_INIT (morse) diff --git a/grub-core/term/serial.c b/grub-core/term/serial.c index ac1fb8394..1c928fe78 100644 --- a/grub-core/term/serial.c +++ b/grub-core/term/serial.c @@ -123,6 +123,7 @@ static struct grub_term_output grub_serial_term_output = .setcursor = grub_terminfo_setcursor, .flags = GRUB_TERM_CODE_TYPE_ASCII, .data = &grub_serial_terminfo_output, + .progress_update_divisor = GRUB_PROGRESS_SLOW }; diff --git a/grub-core/term/spkmodem.c b/grub-core/term/spkmodem.c index 7d4ead356..75c8a0f82 100644 --- a/grub-core/term/spkmodem.c +++ b/grub-core/term/spkmodem.c @@ -126,6 +126,7 @@ static struct grub_term_output grub_spkmodem_term_output = .setcursor = grub_terminfo_setcursor, .flags = GRUB_TERM_CODE_TYPE_ASCII, .data = &grub_spkmodem_terminfo_output, + .progress_update_divisor = GRUB_PROGRESS_NO_UPDATE }; GRUB_MOD_INIT (spkmodem) diff --git a/grub-core/term/uboot/console.c b/grub-core/term/uboot/console.c index 8bf1b3cee..dfdbe9909 100644 --- a/grub-core/term/uboot/console.c +++ b/grub-core/term/uboot/console.c @@ -95,6 +95,7 @@ static struct grub_term_output uboot_console_term_output = { .setcursor = uboot_console_setcursor, .flags = GRUB_TERM_CODE_TYPE_ASCII, .data = &uboot_console_terminfo_output, + .progress_update_divisor = GRUB_PROGRESS_FAST }; void diff --git a/include/grub/file.h b/include/grub/file.h index 8003985e8..f8ae8d9a8 100644 --- a/include/grub/file.h +++ b/include/grub/file.h @@ -28,6 +28,9 @@ /* File description. */ struct grub_file { + /* File name. */ + char *name; + /* The underlying device. */ grub_device_t device; @@ -36,6 +39,12 @@ struct grub_file /* The current offset. */ grub_off_t offset; + grub_off_t progress_offset; + + /* Progress info. */ + grub_uint64_t last_progress_time; + grub_off_t last_progress_offset; + grub_uint64_t estimated_speed; /* The file size. */ grub_off_t size; @@ -54,6 +63,8 @@ struct grub_file }; typedef struct grub_file *grub_file_t; +extern grub_disk_read_hook_t EXPORT_VAR(grub_file_progress_hook); + /* Filters with lower ID are executed first. */ typedef enum grub_file_filter_id { diff --git a/include/grub/term.h b/include/grub/term.h index 9ca0c57a9..9d755a965 100644 --- a/include/grub/term.h +++ b/include/grub/term.h @@ -59,6 +59,10 @@ #define GRUB_TERM_TAB '\t' #define GRUB_TERM_BACKSPACE '\b' +#define GRUB_PROGRESS_NO_UPDATE -1 +#define GRUB_PROGRESS_FAST 0 +#define GRUB_PROGRESS_SLOW 2 + #ifndef ASM_FILE #include @@ -215,6 +219,10 @@ struct grub_term_output /* The feature flags defined above. */ grub_uint32_t flags; + /* Progress data. */ + grub_uint32_t progress_update_divisor; + grub_uint32_t progress_update_counter; + void *data; }; typedef struct grub_term_output *grub_term_output_t;