]> git.proxmox.com Git - grub2.git/blob - grub-core/commands/terminal.c
malloc: Use overflow checking primitives where we do complex allocations
[grub2.git] / grub-core / commands / terminal.c
1 /*
2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2009,2010 Free Software Foundation, Inc.
4 *
5 * GRUB is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * GRUB is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <grub/mm.h>
20 #include <grub/dl.h>
21 #include <grub/command.h>
22 #include <grub/term.h>
23 #include <grub/i18n.h>
24 #include <grub/misc.h>
25
26 GRUB_MOD_LICENSE ("GPLv3+");
27
28 struct grub_term_autoload *grub_term_input_autoload = NULL;
29 struct grub_term_autoload *grub_term_output_autoload = NULL;
30
31 struct abstract_terminal
32 {
33 struct abstract_terminal *next;
34 struct abstract_terminal *prev;
35 const char *name;
36 grub_err_t (*init) (struct abstract_terminal *term);
37 grub_err_t (*fini) (struct abstract_terminal *term);
38 };
39
40 static grub_err_t
41 handle_command (int argc, char **args, struct abstract_terminal **enabled,
42 struct abstract_terminal **disabled,
43 struct grub_term_autoload *autoloads,
44 const char *active_str,
45 const char *available_str)
46 {
47 int i;
48 struct abstract_terminal *term;
49 struct grub_term_autoload *aut;
50
51 if (argc == 0)
52 {
53 grub_puts_ (active_str);
54 for (term = *enabled; term; term = term->next)
55 grub_printf ("%s ", term->name);
56 grub_printf ("\n");
57 grub_puts_ (available_str);
58 for (term = *disabled; term; term = term->next)
59 grub_printf ("%s ", term->name);
60 /* This is quadratic but we don't expect mode than 30 terminal
61 modules ever. */
62 for (aut = autoloads; aut; aut = aut->next)
63 {
64 for (term = *disabled; term; term = term->next)
65 if (grub_strcmp (term->name, aut->name) == 0
66 || (aut->name[0] && aut->name[grub_strlen (aut->name) - 1] == '*'
67 && grub_memcmp (term->name, aut->name,
68 grub_strlen (aut->name) - 1) == 0))
69 break;
70 if (!term)
71 for (term = *enabled; term; term = term->next)
72 if (grub_strcmp (term->name, aut->name) == 0
73 || (aut->name[0] && aut->name[grub_strlen (aut->name) - 1] == '*'
74 && grub_memcmp (term->name, aut->name,
75 grub_strlen (aut->name) - 1) == 0))
76 break;
77 if (!term)
78 grub_printf ("%s ", aut->name);
79 }
80 grub_printf ("\n");
81 return GRUB_ERR_NONE;
82 }
83 i = 0;
84
85 if (grub_strcmp (args[0], "--append") == 0
86 || grub_strcmp (args[0], "--remove") == 0)
87 i++;
88
89 if (i == argc)
90 return grub_error (GRUB_ERR_BAD_ARGUMENT, N_ ("no terminal specified"));
91
92 for (; i < argc; i++)
93 {
94 int again = 0;
95 while (1)
96 {
97 for (term = *disabled; term; term = term->next)
98 if (grub_strcmp (args[i], term->name) == 0
99 || (grub_strcmp (args[i], "ofconsole") == 0
100 && grub_strcmp ("console", term->name) == 0))
101 break;
102 if (term == 0)
103 for (term = *enabled; term; term = term->next)
104 if (grub_strcmp (args[i], term->name) == 0
105 || (grub_strcmp (args[i], "ofconsole") == 0
106 && grub_strcmp ("console", term->name) == 0))
107 break;
108 if (term)
109 break;
110 if (again)
111 return grub_error (GRUB_ERR_BAD_ARGUMENT,
112 N_("terminal `%s' isn't found"),
113 args[i]);
114 for (aut = autoloads; aut; aut = aut->next)
115 if (grub_strcmp (args[i], aut->name) == 0
116 || (grub_strcmp (args[i], "ofconsole") == 0
117 && grub_strcmp ("console", aut->name) == 0)
118 || (aut->name[0] && aut->name[grub_strlen (aut->name) - 1] == '*'
119 && grub_memcmp (args[i], aut->name,
120 grub_strlen (aut->name) - 1) == 0))
121 {
122 grub_dl_t mod;
123 mod = grub_dl_load (aut->modname);
124 if (mod)
125 grub_dl_ref (mod);
126 grub_errno = GRUB_ERR_NONE;
127 break;
128 }
129 if (grub_memcmp (args[i], "serial_usb",
130 sizeof ("serial_usb") - 1) == 0
131 && grub_term_poll_usb)
132 {
133 grub_term_poll_usb (1);
134 again = 1;
135 continue;
136 }
137 if (!aut)
138 return grub_error (GRUB_ERR_BAD_ARGUMENT,
139 N_("terminal `%s' isn't found"),
140 args[i]);
141 again = 1;
142 }
143 }
144
145 if (grub_strcmp (args[0], "--append") == 0)
146 {
147 for (i = 1; i < argc; i++)
148 {
149 for (term = *disabled; term; term = term->next)
150 if (grub_strcmp (args[i], term->name) == 0
151 || (grub_strcmp (args[i], "ofconsole") == 0
152 && grub_strcmp ("console", term->name) == 0))
153 break;
154 if (term)
155 {
156 if (term->init && term->init (term) != GRUB_ERR_NONE)
157 return grub_errno;
158
159 grub_list_remove (GRUB_AS_LIST (term));
160 grub_list_push (GRUB_AS_LIST_P (enabled), GRUB_AS_LIST (term));
161 }
162 }
163 return GRUB_ERR_NONE;
164 }
165
166 if (grub_strcmp (args[0], "--remove") == 0)
167 {
168 for (i = 1; i < argc; i++)
169 {
170 for (term = *enabled; term; term = term->next)
171 if (grub_strcmp (args[i], term->name) == 0
172 || (grub_strcmp (args[i], "ofconsole") == 0
173 && grub_strcmp ("console", term->name) == 0))
174 break;
175 if (term)
176 {
177 if (!term->next && term == *enabled)
178 return grub_error (GRUB_ERR_BAD_ARGUMENT,
179 "can't remove the last terminal");
180 grub_list_remove (GRUB_AS_LIST (term));
181 if (term->fini)
182 term->fini (term);
183 grub_list_push (GRUB_AS_LIST_P (disabled), GRUB_AS_LIST (term));
184 }
185 }
186 return GRUB_ERR_NONE;
187 }
188 for (i = 0; i < argc; i++)
189 {
190 for (term = *disabled; term; term = term->next)
191 if (grub_strcmp (args[i], term->name) == 0
192 || (grub_strcmp (args[i], "ofconsole") == 0
193 && grub_strcmp ("console", term->name) == 0))
194 break;
195 if (term)
196 {
197 if (term->init && term->init (term) != GRUB_ERR_NONE)
198 return grub_errno;
199
200 grub_list_remove (GRUB_AS_LIST (term));
201 grub_list_push (GRUB_AS_LIST_P (enabled), GRUB_AS_LIST (term));
202 }
203 }
204
205 {
206 struct abstract_terminal *next;
207 for (term = *enabled; term; term = next)
208 {
209 next = term->next;
210 for (i = 0; i < argc; i++)
211 if (grub_strcmp (args[i], term->name) == 0
212 || (grub_strcmp (args[i], "ofconsole") == 0
213 && grub_strcmp ("console", term->name) == 0))
214 break;
215 if (i == argc)
216 {
217 if (!term->next && term == *enabled)
218 return grub_error (GRUB_ERR_BAD_ARGUMENT,
219 "can't remove the last terminal");
220 grub_list_remove (GRUB_AS_LIST (term));
221 if (term->fini)
222 term->fini (term);
223 grub_list_push (GRUB_AS_LIST_P (disabled), GRUB_AS_LIST (term));
224 }
225 }
226 }
227
228 return GRUB_ERR_NONE;
229 }
230
231 static grub_err_t
232 grub_cmd_terminal_input (grub_command_t cmd __attribute__ ((unused)),
233 int argc, char **args)
234 {
235 (void) GRUB_FIELD_MATCH (grub_term_inputs, struct abstract_terminal *, next);
236 (void) GRUB_FIELD_MATCH (grub_term_inputs, struct abstract_terminal *, prev);
237 (void) GRUB_FIELD_MATCH (grub_term_inputs, struct abstract_terminal *, name);
238 (void) GRUB_FIELD_MATCH (grub_term_inputs, struct abstract_terminal *, init);
239 (void) GRUB_FIELD_MATCH (grub_term_inputs, struct abstract_terminal *, fini);
240 return handle_command (argc, args,
241 (struct abstract_terminal **) (void *) &grub_term_inputs,
242 (struct abstract_terminal **) (void *) &grub_term_inputs_disabled,
243 grub_term_input_autoload,
244 N_ ("Active input terminals:"),
245 N_ ("Available input terminals:"));
246 }
247
248 static grub_err_t
249 grub_cmd_terminal_output (grub_command_t cmd __attribute__ ((unused)),
250 int argc, char **args)
251 {
252 (void) GRUB_FIELD_MATCH (grub_term_outputs, struct abstract_terminal *, next);
253 (void) GRUB_FIELD_MATCH (grub_term_outputs, struct abstract_terminal *, prev);
254 (void) GRUB_FIELD_MATCH (grub_term_outputs, struct abstract_terminal *, name);
255 (void) GRUB_FIELD_MATCH (grub_term_outputs, struct abstract_terminal *, init);
256 (void) GRUB_FIELD_MATCH (grub_term_outputs, struct abstract_terminal *, fini);
257 return handle_command (argc, args,
258 (struct abstract_terminal **) (void *) &grub_term_outputs,
259 (struct abstract_terminal **) (void *) &grub_term_outputs_disabled,
260 grub_term_output_autoload,
261 N_ ("Active output terminals:"),
262 N_ ("Available output terminals:"));
263 }
264
265 static grub_command_t cmd_terminal_input, cmd_terminal_output;
266
267 GRUB_MOD_INIT(terminal)
268 {
269 cmd_terminal_input =
270 grub_register_command ("terminal_input", grub_cmd_terminal_input,
271 N_("[--append|--remove] "
272 "[TERMINAL1] [TERMINAL2] ..."),
273 N_("List or select an input terminal."));
274 cmd_terminal_output =
275 grub_register_command ("terminal_output", grub_cmd_terminal_output,
276 N_("[--append|--remove] "
277 "[TERMINAL1] [TERMINAL2] ..."),
278 N_("List or select an output terminal."));
279 }
280
281 GRUB_MOD_FINI(terminal)
282 {
283 grub_unregister_command (cmd_terminal_input);
284 grub_unregister_command (cmd_terminal_output);
285 }