48ba1a44e1
1 OBS-URL: https://build.opensuse.org/request/show/296732 OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/grub2?expand=0&rev=113
531 lines
15 KiB
Diff
531 lines
15 KiB
Diff
Vn:
|
||
* recognize 'dev/sclp_line0' as 3215-look-alike. [bnc#876743]
|
||
Vn+1:
|
||
* revamp readkey_dumb().
|
||
Vn+2:
|
||
* support hotkeys on all line-mode terminals, not only 3215. [bnc#885668]
|
||
|
||
---
|
||
grub-core/kern/emu/main.c | 8 +
|
||
grub-core/normal/menu_text.c | 54 +++++++-
|
||
grub-core/normal/term.c | 2
|
||
grub-core/osdep/unix/emuconsole.c | 238 +++++++++++++++++++++++++++++++++++++-
|
||
include/grub/term.h | 4
|
||
5 files changed, 294 insertions(+), 12 deletions(-)
|
||
|
||
--- a/grub-core/osdep/unix/emuconsole.c
|
||
+++ b/grub-core/osdep/unix/emuconsole.c
|
||
@@ -39,17 +39,61 @@
|
||
|
||
#include <grub/emu/console.h>
|
||
|
||
+#include <stdio.h>
|
||
+#include <errno.h>
|
||
+
|
||
extern struct grub_terminfo_output_state grub_console_terminfo_output;
|
||
static int original_fl;
|
||
static int saved_orig;
|
||
static struct termios orig_tty;
|
||
static struct termios new_tty;
|
||
+static int console_mode = 0;
|
||
+
|
||
+#define MAX_LEN 1023
|
||
+#if defined(__s390x__)
|
||
+static int
|
||
+dummy (void)
|
||
+{
|
||
+ return 0;
|
||
+}
|
||
+#endif
|
||
+#if 0
|
||
+static char msg[MAX_LEN+1];
|
||
+static void
|
||
+dprint (int len)
|
||
+{
|
||
+ if (len < 0)
|
||
+ return;
|
||
+ if (len > MAX_LEN)
|
||
+ len = MAX_LEN;
|
||
+ write (2, msg, len);
|
||
+}
|
||
+#define dprintf(fmt, vargs...) dprint(snprintf(msg, MAX_LEN, fmt, ## vargs))
|
||
+#else
|
||
+#define dprintf(fmt, vargs...) {}
|
||
+#endif
|
||
|
||
static void
|
||
-put (struct grub_term_output *term __attribute__ ((unused)), const int c)
|
||
+put (struct grub_term_output *term, const int c)
|
||
{
|
||
char chr = c;
|
||
ssize_t actual;
|
||
+ struct grub_terminfo_output_state *data
|
||
+ = (struct grub_terminfo_output_state *) term->data;
|
||
+
|
||
+ if (term->flags & GRUB_TERM_DUMB) {
|
||
+ if (c == '\n') {
|
||
+ data->pos.y++;
|
||
+ data->pos.x = 0;
|
||
+ } else {
|
||
+ data->pos.x++;
|
||
+ }
|
||
+ if (0) {
|
||
+ if (c == ' ') chr = '_';
|
||
+ if (c == GRUB_TERM_BACKSPACE) chr = '{';
|
||
+ if (c == '\b') chr = '<';
|
||
+ }
|
||
+ }
|
||
|
||
actual = write (STDOUT_FILENO, &chr, 1);
|
||
if (actual < 1)
|
||
@@ -60,17 +104,152 @@ put (struct grub_term_output *term __att
|
||
}
|
||
|
||
static int
|
||
-readkey (struct grub_term_input *term __attribute__ ((unused)))
|
||
+readkey (struct grub_term_input *term)
|
||
{
|
||
grub_uint8_t c;
|
||
ssize_t actual;
|
||
|
||
+ fd_set readfds;
|
||
+ struct timeval timeout;
|
||
+ int sel;
|
||
+ FD_SET (0, &readfds);
|
||
+ timeout.tv_sec = 0;
|
||
+ timeout.tv_usec = 500000;
|
||
+ if ((sel=select (1, &readfds, (fd_set *)0, (fd_set *)0, &timeout)) <= 0)
|
||
+ {
|
||
+ if (sel < 0 && errno == EINTR)
|
||
+ return 0x03; /* '^C' */
|
||
+ return -1;
|
||
+ }
|
||
+
|
||
actual = read (STDIN_FILENO, &c, 1);
|
||
if (actual > 0)
|
||
return c;
|
||
return -1;
|
||
}
|
||
|
||
+#define NO_KEY ((grub_uint8_t)-1)
|
||
+static int
|
||
+readkey_dumb (struct grub_term_input *term)
|
||
+{
|
||
+ grub_uint8_t c;
|
||
+ static grub_uint8_t p = NO_KEY;
|
||
+
|
||
+ c = readkey (term);
|
||
+ if (c == NO_KEY)
|
||
+ return -1;
|
||
+ if ((p == '^' || p == '\n') && c == '\n') /* solitary '^' or '\n'? */
|
||
+ {
|
||
+ c = p; /* use immediately! */
|
||
+ p = '\n';
|
||
+ }
|
||
+ else if ((c == '\n' || c == '^') && p != c) /* non-duplicate specials? */
|
||
+ {
|
||
+ p = c; /* remember! */
|
||
+ c = NO_KEY;
|
||
+ }
|
||
+ else if (p == '^')
|
||
+ {
|
||
+ if (c != '^')
|
||
+ c &= 0x1F;
|
||
+ p = NO_KEY;
|
||
+ }
|
||
+ else
|
||
+ p = c;
|
||
+ return c;
|
||
+}
|
||
+
|
||
+static void
|
||
+grub_dumb_putchar (struct grub_term_output *term,
|
||
+ const struct grub_unicode_glyph *c)
|
||
+{
|
||
+ unsigned i;
|
||
+
|
||
+ /* For now, do not try to use a surrogate pair. */
|
||
+ if (c->base > 0xffff)
|
||
+ put (term, '?');
|
||
+ else
|
||
+ put (term, (c->base & 0xffff));
|
||
+
|
||
+ if (0) {
|
||
+ for (i = 0; i < c->ncomb; i++)
|
||
+ if (c->base < 0xffff)
|
||
+ put (term, grub_unicode_get_comb (c)[i].code);
|
||
+ }
|
||
+}
|
||
+
|
||
+static struct grub_term_coordinate
|
||
+grub_dumb_getxy (struct grub_term_output *term)
|
||
+{
|
||
+ struct grub_terminfo_output_state *data
|
||
+ = (struct grub_terminfo_output_state *) term->data;
|
||
+
|
||
+ dprintf ("<%d,%d>", data->pos.x, data->pos.y);
|
||
+ return data->pos;
|
||
+}
|
||
+
|
||
+static struct grub_term_coordinate
|
||
+grub_dumb_getwh (struct grub_term_output *term)
|
||
+{
|
||
+ static int once = 0;
|
||
+ struct grub_terminfo_output_state *data
|
||
+ = (struct grub_terminfo_output_state *) term->data;
|
||
+
|
||
+ if (!once++)
|
||
+ dprintf ("dumb_getwh: w=%d h=%d\n", data->size.x, data->size.y);
|
||
+ return data->size;
|
||
+}
|
||
+
|
||
+static void
|
||
+grub_dumb_gotoxy (struct grub_term_output *term,
|
||
+ struct grub_term_coordinate pos)
|
||
+{
|
||
+ struct grub_terminfo_output_state *data
|
||
+ = (struct grub_terminfo_output_state *) term->data;
|
||
+
|
||
+ if (pos.x > grub_term_width (term) || pos.y > grub_term_height (term))
|
||
+ {
|
||
+ grub_error (GRUB_ERR_BUG, "invalid point (%u,%u)", pos.x, pos.y);
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ dprintf("goto(%d,%d)", pos.x, pos.y);
|
||
+ if (pos.x > (grub_term_width (term) - 4)) {
|
||
+ dprintf (" really?");
|
||
+ //return;
|
||
+ }
|
||
+
|
||
+ if (data->gotoxy)
|
||
+ {
|
||
+ int i;
|
||
+ dprintf ("data-gotoxy");
|
||
+ if (data->pos.y != pos.y) {
|
||
+ put (term, '\n');
|
||
+
|
||
+ for (i = 1; i < pos.x; i++ )
|
||
+ put (term, ' ');
|
||
+ }
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ int i = 0;
|
||
+ if (data->pos.y != pos.y || data->pos.x > pos.x) {
|
||
+ if (data->pos.y >= pos.y) data->pos.y = pos.y - 1;
|
||
+ if (pos.y - data->pos.y > 3) data->pos.y = pos.y - 2;
|
||
+ dprintf (" <%dnl>+%d", (pos.y - data->pos.y), pos.x);
|
||
+ for (i = data->pos.y; i < pos.y; i++ )
|
||
+ put (term, '\n');
|
||
+ }
|
||
+ for (i = data->pos.x; i < pos.x; i++ )
|
||
+ put (term, ' ');
|
||
+ dprintf ("#%d", i);
|
||
+ grub_dumb_getxy (term);
|
||
+ }
|
||
+
|
||
+ dprintf ("\n");
|
||
+ data->pos = pos;
|
||
+}
|
||
+
|
||
static grub_err_t
|
||
grub_console_init_input (struct grub_term_input *term)
|
||
{
|
||
@@ -105,7 +284,8 @@ static grub_err_t
|
||
grub_console_init_output (struct grub_term_output *term)
|
||
{
|
||
struct winsize size;
|
||
- if (ioctl (STDOUT_FILENO, TIOCGWINSZ, &size) >= 0)
|
||
+ if (ioctl (STDOUT_FILENO, TIOCGWINSZ, &size) >= 0 &&
|
||
+ size.ws_col > 0 && size.ws_row > 0)
|
||
{
|
||
grub_console_terminfo_output.size.x = size.ws_col;
|
||
grub_console_terminfo_output.size.y = size.ws_row;
|
||
@@ -115,6 +295,8 @@ grub_console_init_output (struct grub_te
|
||
grub_console_terminfo_output.size.x = 80;
|
||
grub_console_terminfo_output.size.y = 24;
|
||
}
|
||
+ if (console_mode == 3215)
|
||
+ grub_console_terminfo_output.size.x -= 1;
|
||
|
||
grub_terminfo_output_init (term);
|
||
|
||
@@ -161,24 +343,72 @@ static struct grub_term_output grub_cons
|
||
void
|
||
grub_console_init (void)
|
||
{
|
||
+#if ! defined(__s390x__)
|
||
const char *cs = nl_langinfo (CODESET);
|
||
if (cs && grub_strcasecmp (cs, "UTF-8"))
|
||
grub_console_term_output.flags = GRUB_TERM_CODE_TYPE_UTF8_LOGICAL;
|
||
else
|
||
grub_console_term_output.flags = GRUB_TERM_CODE_TYPE_ASCII;
|
||
+#else
|
||
+ char link[MAX_LEN+1];
|
||
+ ssize_t len = readlink ("/proc/self/fd/0", link, MAX_LEN);
|
||
+
|
||
+ if (len > 0)
|
||
+ link[len] = 0;
|
||
+ else
|
||
+ link[0] = 0;
|
||
+ if (grub_strncmp ("/dev/ttyS", link, 9) == 0 )
|
||
+ console_mode = 3215;
|
||
+ else if (grub_strncmp ("/dev/3270/tty", link, 13) == 0 )
|
||
+ console_mode = 3270;
|
||
+ else if (grub_strncmp ("/dev/sclp_line", link, 14) == 0 )
|
||
+ console_mode = 3215;
|
||
+ grub_console_term_output.flags = GRUB_TERM_CODE_TYPE_ASCII;
|
||
+ switch (console_mode)
|
||
+ {
|
||
+ case 3215:
|
||
+ grub_console_term_output.flags |= GRUB_TERM_DUMB;
|
||
+ /* FALLTHROUGH */
|
||
+ case 3270:
|
||
+ grub_console_term_output.flags |= GRUB_TERM_LINE;
|
||
+ grub_console_term_output.flags |= GRUB_TERM_NO_ECHO;
|
||
+ grub_console_terminfo_input.readkey = readkey_dumb;
|
||
+ break;
|
||
+ default:
|
||
+ break;
|
||
+ }
|
||
+#endif
|
||
+ if (grub_console_term_output.flags & GRUB_TERM_DUMB)
|
||
+ {
|
||
+ grub_console_term_output.putchar = grub_dumb_putchar,
|
||
+ grub_console_term_output.getxy = grub_dumb_getxy;
|
||
+ grub_console_term_output.getwh = grub_dumb_getwh;
|
||
+ grub_console_term_output.gotoxy = grub_dumb_gotoxy;
|
||
+ grub_console_term_output.cls = (void *) dummy;
|
||
+ grub_console_term_output.setcolorstate = (void *) dummy;
|
||
+ grub_console_term_output.setcursor = (void *) dummy;
|
||
+ grub_console_term_output.progress_update_divisor = GRUB_PROGRESS_NO_UPDATE;
|
||
+ }
|
||
grub_term_register_input ("console", &grub_console_term_input);
|
||
grub_term_register_output ("console", &grub_console_term_output);
|
||
grub_terminfo_init ();
|
||
- grub_terminfo_output_register (&grub_console_term_output, "vt100-color");
|
||
+ grub_terminfo_output_register (&grub_console_term_output,
|
||
+ (grub_console_term_output.flags & GRUB_TERM_DUMB) ? "dumb":"vt100-color");
|
||
}
|
||
|
||
void
|
||
grub_console_fini (void)
|
||
{
|
||
+ dprintf( "grub_console_fini: %d\n", grub_console_term_output.flags & GRUB_TERM_DUMB);
|
||
if (saved_orig)
|
||
{
|
||
fcntl (STDIN_FILENO, F_SETFL, original_fl);
|
||
tcsetattr(STDIN_FILENO, TCSANOW, &orig_tty);
|
||
}
|
||
+ if (!(grub_console_term_output.flags & GRUB_TERM_DUMB))
|
||
+ {
|
||
+ const char clear[] = { 0x1b, 'c', 0 };
|
||
+ write (STDOUT_FILENO, clear, 2);
|
||
+ }
|
||
saved_orig = 0;
|
||
}
|
||
--- a/grub-core/normal/menu_text.c
|
||
+++ b/grub-core/normal/menu_text.c
|
||
@@ -113,6 +113,7 @@ draw_border (struct grub_term_output *te
|
||
{
|
||
int i;
|
||
|
||
+ if (! (term->flags & GRUB_TERM_DUMB)) {
|
||
grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
|
||
|
||
grub_term_gotoxy (term, (struct grub_term_coordinate) { geo->first_entry_x - 1,
|
||
@@ -142,7 +143,7 @@ draw_border (struct grub_term_output *te
|
||
grub_putcode (GRUB_UNICODE_CORNER_LR, term);
|
||
|
||
grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
|
||
-
|
||
+ }
|
||
grub_term_gotoxy (term,
|
||
(struct grub_term_coordinate) { geo->first_entry_x - 1,
|
||
(geo->first_entry_y - 1 + geo->num_entries
|
||
@@ -155,6 +156,15 @@ print_message (int nested, int edit, str
|
||
int ret = 0;
|
||
grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
|
||
|
||
+ if (edit && (term->flags & GRUB_TERM_LINE))
|
||
+ {
|
||
+ ret += grub_print_message_indented_real
|
||
+ (_("Minimum Emacs-like screen editing is supported. '^i' lists "
|
||
+ "completions. Type '^x' to boot, '^c' for a command-line "
|
||
+ "or '^[' to discard edits and return to the GRUB menu."),
|
||
+ STANDARD_MARGIN, STANDARD_MARGIN, term, dry_run);
|
||
+ }
|
||
+ else
|
||
if (edit)
|
||
{
|
||
ret += grub_print_message_indented_real (_("Minimum Emacs-like screen editing is \
|
||
@@ -165,10 +175,15 @@ command-line or ESC to discard edits and
|
||
}
|
||
else
|
||
{
|
||
+#if defined(__s390x__hotkey)
|
||
+ ret += grub_print_message_indented_real
|
||
+ (_("Select a menu option by pressing the hotkey specified. "),
|
||
+ STANDARD_MARGIN, STANDARD_MARGIN, term, dry_run);
|
||
+#else
|
||
char *msg_translated;
|
||
|
||
msg_translated = grub_xasprintf (_("Use the %C and %C keys to select which "
|
||
- "entry is highlighted."),
|
||
+ "entry is highlighted. "),
|
||
GRUB_UNICODE_UPARROW,
|
||
GRUB_UNICODE_DOWNARROW);
|
||
if (!msg_translated)
|
||
@@ -177,6 +192,7 @@ command-line or ESC to discard edits and
|
||
STANDARD_MARGIN, term, dry_run);
|
||
|
||
grub_free (msg_translated);
|
||
+#endif
|
||
|
||
if (nested)
|
||
{
|
||
@@ -211,6 +227,10 @@ print_entry (int y, int highlight, grub_
|
||
|
||
title = entry ? entry->title : "";
|
||
title_len = grub_strlen (title);
|
||
+
|
||
+ if ((data->term->flags & GRUB_TERM_DUMB) && title[0] == '\0')
|
||
+ return;
|
||
+
|
||
unicode_title = grub_malloc (title_len * sizeof (*unicode_title));
|
||
if (! unicode_title)
|
||
/* XXX How to show this error? */
|
||
@@ -244,6 +264,14 @@ print_entry (int y, int highlight, grub_
|
||
if (data->geo.num_entries > 1)
|
||
grub_putcode (highlight ? '*' : ' ', data->term);
|
||
|
||
+ if ((data->term->flags & GRUB_TERM_LINE) && title[0] != '\0') {
|
||
+ grub_putcode('(', data->term);
|
||
+ grub_putcode((entry && entry->hotkey >= '0' && entry->hotkey <= 'z') ?
|
||
+ entry->hotkey : ' ', data->term);
|
||
+ grub_putcode(')', data->term);
|
||
+ grub_putcode(' ', data->term);
|
||
+ }
|
||
+
|
||
grub_print_ucs4_menu (unicode_title,
|
||
unicode_title + len,
|
||
0,
|
||
@@ -413,6 +441,8 @@ grub_menu_init_page (int nested, int edi
|
||
grub_term_highlight_color = old_color_highlight;
|
||
geo->timeout_y = geo->first_entry_y + geo->num_entries
|
||
+ geo->border + empty_lines;
|
||
+ if (term->flags & GRUB_TERM_DUMB)
|
||
+ geo->timeout_y = 1;
|
||
if (bottom_message)
|
||
{
|
||
grub_term_gotoxy (term,
|
||
@@ -422,6 +452,8 @@ grub_menu_init_page (int nested, int edi
|
||
print_message (nested, edit, term, 0);
|
||
geo->timeout_y += msg_num_lines;
|
||
}
|
||
+ if (term->flags & GRUB_TERM_DUMB)
|
||
+ geo->timeout_y = 1;
|
||
geo->right_margin = grub_term_width (term)
|
||
- geo->first_entry_x
|
||
- geo->entry_width - 1;
|
||
@@ -433,12 +465,19 @@ menu_text_print_timeout (int timeout, vo
|
||
struct menu_viewer_data *data = dataptr;
|
||
char *msg_translated = 0;
|
||
|
||
- grub_term_gotoxy (data->term,
|
||
+ if (data->geo.timeout_y)
|
||
+ grub_term_gotoxy (data->term,
|
||
(struct grub_term_coordinate) { 0, data->geo.timeout_y });
|
||
|
||
+ if (data->term->flags & GRUB_TERM_DUMB)
|
||
+ {
|
||
+ if (! data->geo.timeout_y)
|
||
+ data->timeout_msg = TIMEOUT_TERSE;
|
||
+ data->geo.timeout_y = 0;
|
||
+ }
|
||
if (data->timeout_msg == TIMEOUT_TERSE
|
||
|| data->timeout_msg == TIMEOUT_TERSE_NO_MARGIN)
|
||
- msg_translated = grub_xasprintf (_("%ds"), timeout);
|
||
+ msg_translated = grub_xasprintf (_(" %ds"), timeout);
|
||
else
|
||
msg_translated = grub_xasprintf (_("The highlighted entry will be executed automatically in %ds."), timeout);
|
||
if (!msg_translated)
|
||
@@ -468,6 +507,8 @@ menu_text_print_timeout (int timeout, vo
|
||
data->term);
|
||
grub_free (msg_translated);
|
||
|
||
+ if (data->term->flags & GRUB_TERM_DUMB)
|
||
+ return;
|
||
grub_term_gotoxy (data->term,
|
||
(struct grub_term_coordinate) {
|
||
grub_term_cursor_x (&data->geo),
|
||
@@ -495,7 +536,7 @@ menu_text_set_chosen_entry (int entry, v
|
||
data->first = entry;
|
||
complete_redraw = 1;
|
||
}
|
||
- if (complete_redraw)
|
||
+ if (complete_redraw || (data->term->flags & GRUB_TERM_DUMB))
|
||
print_entries (data->menu, data);
|
||
else
|
||
{
|
||
@@ -525,6 +566,9 @@ menu_text_clear_timeout (void *dataptr)
|
||
struct menu_viewer_data *data = dataptr;
|
||
int i;
|
||
|
||
+ if ((data->term->flags & GRUB_TERM_DUMB))
|
||
+ return;
|
||
+
|
||
for (i = 0; i < data->geo.timeout_lines;i++)
|
||
{
|
||
grub_term_gotoxy (data->term, (struct grub_term_coordinate) {
|
||
--- a/grub-core/normal/term.c
|
||
+++ b/grub-core/normal/term.c
|
||
@@ -981,7 +981,7 @@ grub_print_ucs4_menu (const grub_uint32_
|
||
{
|
||
print_ucs4_real (str, last_position, margin_left, margin_right,
|
||
term, 0, 0, 1, skip_lines, max_lines,
|
||
- contchar, 1, pos);
|
||
+ contchar, (term->flags & GRUB_TERM_DUMB)? 0 : 1, pos);
|
||
}
|
||
|
||
void
|
||
--- a/grub-core/kern/emu/main.c
|
||
+++ b/grub-core/kern/emu/main.c
|
||
@@ -174,6 +174,12 @@ static struct argp argp = {
|
||
NULL, help_filter, NULL
|
||
};
|
||
|
||
+void
|
||
+ignore (int num __attribute__ ((unused)))
|
||
+{
|
||
+ return;
|
||
+}
|
||
+
|
||
|
||
|
||
#pragma GCC diagnostic ignored "-Wmissing-prototypes"
|
||
@@ -212,7 +218,7 @@ main (int argc, char *argv[])
|
||
sleep (1);
|
||
}
|
||
|
||
- signal (SIGINT, SIG_IGN);
|
||
+ signal (SIGINT, (sighandler_t) &ignore);
|
||
grub_console_init ();
|
||
grub_host_init ();
|
||
|
||
--- a/include/grub/term.h
|
||
+++ b/include/grub/term.h
|
||
@@ -99,8 +99,10 @@ grub_term_color_state;
|
||
#define GRUB_TERM_NO_EDIT (1 << 1)
|
||
/* Set when the terminal cannot do fancy things. */
|
||
#define GRUB_TERM_DUMB (1 << 2)
|
||
+/* Set when the terminal is line oriented. */
|
||
+#define GRUB_TERM_LINE (1 << 3)
|
||
/* Which encoding does terminal expect stream to be. */
|
||
-#define GRUB_TERM_CODE_TYPE_SHIFT 3
|
||
+#define GRUB_TERM_CODE_TYPE_SHIFT 4
|
||
#define GRUB_TERM_CODE_TYPE_MASK (7 << GRUB_TERM_CODE_TYPE_SHIFT)
|
||
/* Only ASCII characters accepted. */
|
||
#define GRUB_TERM_CODE_TYPE_ASCII (0 << GRUB_TERM_CODE_TYPE_SHIFT)
|