* 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 Paulo Flabiano Smorigo <pfsmorigo@br.ibm.com>
+
+ 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 <phcoder@gmail.com>
Verify signatures of signatures unless --skip-sig is specified.
name = tr;
common = commands/tr.c;
};
+
+module = {
+ name = progress;
+ common = lib/progress.c;
+};
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
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
if (! file)
goto fail;
+ file->name = grub_strdup (name);
+ grub_errno = GRUB_ERR_NONE;
+
file->device = device;
if (device->disk && file_name[0] != '/')
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)
{
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;
--- /dev/null
+/* 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>
+
+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;
+}
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);
.setcolorstate = grub_terminfo_setcolorstate,
.setcursor = grub_terminfo_setcursor,
.data = &grub_console_terminfo_output,
+ .progress_update_divisor = GRUB_PROGRESS_FAST
};
void
.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
.setcursor = grub_terminfo_setcursor,
.flags = GRUB_TERM_CODE_TYPE_ASCII,
.data = &grub_console_terminfo_output,
+ .progress_update_divisor = GRUB_PROGRESS_FAST
};
void
.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
.refresh = grub_gfxterm_refresh,
.fullscreen = grub_gfxterm_fullscreen,
.flags = GRUB_TERM_CODE_TYPE_VISUAL_GLYPHS,
+ .progress_update_divisor = GRUB_PROGRESS_SLOW,
.next = 0
};
.setcursor = grub_terminfo_setcursor,
.flags = GRUB_TERM_CODE_TYPE_ASCII,
.data = &grub_cbmemc_terminfo_output,
+ .progress_update_divisor = GRUB_PROGRESS_NO_UPDATE
};
static int
.setcolorstate = grub_console_setcolorstate,
.setcursor = grub_console_setcursor,
.flags = GRUB_TERM_CODE_TYPE_CP437,
+ .progress_update_divisor = GRUB_PROGRESS_FAST
};
void
.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. */
.setcursor = grub_console_setcursor,
.flags = GRUB_TERM_CODE_TYPE_ASCII,
.data = &grub_console_terminfo_output,
+ .progress_update_divisor = GRUB_PROGRESS_FAST
};
void
.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)
.setcursor = grub_terminfo_setcursor,
.flags = GRUB_TERM_CODE_TYPE_ASCII,
.data = &grub_serial_terminfo_output,
+ .progress_update_divisor = GRUB_PROGRESS_SLOW
};
\f
.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)
.setcursor = uboot_console_setcursor,
.flags = GRUB_TERM_CODE_TYPE_ASCII,
.data = &uboot_console_terminfo_output,
+ .progress_update_divisor = GRUB_PROGRESS_FAST
};
void
/* File description. */
struct grub_file
{
+ /* File name. */
+ char *name;
+
/* The underlying device. */
grub_device_t device;
/* 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;
};
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
{
#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 <grub/err.h>
/* 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;