2 * Copyright (C) 2017 IBM Corporation
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; version 2 of the License.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
15 #if defined(HAVE_CONFIG_H)
25 #include "talloc/talloc.h"
27 #ifndef PETITBOOT_TEST
32 #include "console-codes.h"
36 #define INTER_CHAR_START 040
37 #define INTER_CHAR_END 057
38 #define ESC_SEQUENCE_FINAL_START 060
39 #define ESC_SEQUENCE_FINAL_END 0176
40 #define CTRL_SEQUENCE_FINAL_START 0100
41 #define CTRL_SEQUENCE_FINAL_END 0176
42 #define DEC_PARAMETER 077
44 enum console_sequence_state {
46 CONSOLE_STATE_ESC_SEQ,
47 CONSOLE_STATE_CTRL_SEQ_START,
48 CONSOLE_STATE_CTRL_SEQ,
50 CONSOLE_STATE_CONFUSED,
53 static inline bool is_intermediate(signed char c)
55 return c > INTER_CHAR_START && c < INTER_CHAR_END;
58 static inline bool is_parameter(signed char c)
60 return (c >= 060 && c <= 071) || c == 073;
63 static inline bool is_escape_final(signed char c)
65 return c >= ESC_SEQUENCE_FINAL_START && c < ESC_SEQUENCE_FINAL_END;
68 static inline bool is_control_final(signed char c)
70 return c >= CTRL_SEQUENCE_FINAL_START && c <= CTRL_SEQUENCE_FINAL_END;
73 static char console_sequence_getch(char **sequence)
75 signed char c = getch();
78 *sequence = talloc_asprintf_append(*sequence, "%c", c);
83 * Catch terminal control sequences that have accidentally been sent to
84 * Petitboot. These are of the form
86 * where I is an Intermediate Character and F is a Final Character, eg:
90 * This is based off the definitions provided by
91 * https://vt100.net/docs/vt100-ug/contents.html
93 char *handle_control_sequence(void *ctx, signed char start)
95 enum console_sequence_state state = CONSOLE_STATE_START;
96 bool in_sequence = true;
100 if (start != ESC_CHAR) {
101 pb_log("%s: Called with non-escape character: 0%o\n",
106 seq = talloc_asprintf(ctx, "%c", start);
108 while (in_sequence) {
110 case CONSOLE_STATE_START:
111 c = console_sequence_getch(&seq);
113 state = CONSOLE_STATE_CTRL_SEQ_START;
114 else if (is_intermediate(c))
115 state = CONSOLE_STATE_ESC_SEQ;
116 else if (is_escape_final(c))
117 state = CONSOLE_STATE_DONE;
119 /* wait on c == ERR */
120 pb_debug("Unexpected start: \\x%x\n", c);
121 state = CONSOLE_STATE_CONFUSED;
124 case CONSOLE_STATE_ESC_SEQ:
125 c = console_sequence_getch(&seq);
126 if (is_intermediate(c))
127 state = CONSOLE_STATE_ESC_SEQ;
128 else if (is_escape_final(c))
129 state = CONSOLE_STATE_DONE;
131 /* wait on c == ERR */
132 pb_debug("Unexpected character after intermediate: \\x%x\n",
134 state = CONSOLE_STATE_CONFUSED;
137 case CONSOLE_STATE_CTRL_SEQ_START:
138 c = console_sequence_getch(&seq);
139 if (is_intermediate(c) || is_parameter(c) ||
141 state = CONSOLE_STATE_CTRL_SEQ;
142 else if (is_control_final(c))
143 state = CONSOLE_STATE_DONE;
145 /* wait on c == ERR */
146 pb_debug("Unexpected character in param string: \\x%x\n",
148 state = CONSOLE_STATE_CONFUSED;
151 case CONSOLE_STATE_CTRL_SEQ:
152 c = console_sequence_getch(&seq);
153 if (is_intermediate(c) || is_parameter(c))
154 state = CONSOLE_STATE_CTRL_SEQ;
155 else if (is_control_final(c))
156 state = CONSOLE_STATE_DONE;
158 /* wait on c == ERR */
159 pb_debug("Unexpected character in param string: \\x%x\n",
161 state = CONSOLE_STATE_CONFUSED;
164 case CONSOLE_STATE_DONE:
167 case CONSOLE_STATE_CONFUSED:
170 pb_debug("We got lost interpreting a control sequence!\n");
171 seq = talloc_asprintf_append(seq, "...");