]>
Commit | Line | Data |
---|---|---|
0aa63398 VS |
1 | /* |
2 | * GRUB -- GRand Unified Bootloader | |
9444b678 | 3 | * Copyright (C) 2009,2010 Free Software Foundation, Inc. |
0aa63398 VS |
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 | ||
e745cf0c VS |
26 | GRUB_MOD_LICENSE ("GPLv3+"); |
27 | ||
33c1ed4c VS |
28 | struct grub_term_autoload *grub_term_input_autoload = NULL; |
29 | struct grub_term_autoload *grub_term_output_autoload = NULL; | |
30 | ||
6f8aaf68 VS |
31 | struct abstract_terminal |
32 | { | |
33 | struct abstract_terminal *next; | |
87edb894 | 34 | struct abstract_terminal *prev; |
6f8aaf68 | 35 | const char *name; |
58664b94 VS |
36 | grub_err_t (*init) (struct abstract_terminal *term); |
37 | grub_err_t (*fini) (struct abstract_terminal *term); | |
6f8aaf68 VS |
38 | }; |
39 | ||
d8a1cbbd | 40 | static grub_err_t |
6f8aaf68 VS |
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) | |
0aa63398 VS |
46 | { |
47 | int i; | |
6f8aaf68 | 48 | struct abstract_terminal *term; |
33c1ed4c | 49 | struct grub_term_autoload *aut; |
0aa63398 VS |
50 | |
51 | if (argc == 0) | |
52 | { | |
6f8aaf68 VS |
53 | grub_puts_ (active_str); |
54 | for (term = *enabled; term; term = term->next) | |
55 | grub_printf ("%s ", term->name); | |
0aa63398 | 56 | grub_printf ("\n"); |
6f8aaf68 VS |
57 | grub_puts_ (available_str); |
58 | for (term = *disabled; term; term = term->next) | |
59 | grub_printf ("%s ", term->name); | |
33c1ed4c | 60 | /* This is quadratic but we don't expect mode than 30 terminal |
6f8aaf68 VS |
61 | modules ever. */ |
62 | for (aut = autoloads; aut; aut = aut->next) | |
63 | { | |
64 | for (term = *disabled; term; term = term->next) | |
75eb7d11 VS |
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)) | |
6f8aaf68 VS |
69 | break; |
70 | if (!term) | |
71 | for (term = *enabled; term; term = term->next) | |
75eb7d11 VS |
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)) | |
6f8aaf68 VS |
76 | break; |
77 | if (!term) | |
78 | grub_printf ("%s ", aut->name); | |
79 | } | |
0aa63398 VS |
80 | grub_printf ("\n"); |
81 | return GRUB_ERR_NONE; | |
82 | } | |
83 | i = 0; | |
84 | ||
85 | if (grub_strcmp (args[0], "--append") == 0 | |
abd1cab3 | 86 | || grub_strcmp (args[0], "--remove") == 0) |
0aa63398 VS |
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 | { | |
33c1ed4c VS |
94 | int again = 0; |
95 | while (1) | |
6f8aaf68 VS |
96 | { |
97 | for (term = *disabled; term; term = term->next) | |
ca8c0baf VS |
98 | if (grub_strcmp (args[i], term->name) == 0 |
99 | || (grub_strcmp (args[i], "ofconsole") == 0 | |
100 | && grub_strcmp ("console", term->name) == 0)) | |
6f8aaf68 VS |
101 | break; |
102 | if (term == 0) | |
103 | for (term = *enabled; term; term = term->next) | |
ca8c0baf VS |
104 | if (grub_strcmp (args[i], term->name) == 0 |
105 | || (grub_strcmp (args[i], "ofconsole") == 0 | |
106 | && grub_strcmp ("console", term->name) == 0)) | |
6f8aaf68 VS |
107 | break; |
108 | if (term) | |
109 | break; | |
110 | if (again) | |
d745dda7 | 111 | return grub_error (GRUB_ERR_BAD_ARGUMENT, |
d61386e2 | 112 | N_("terminal `%s' isn't found"), |
d745dda7 | 113 | args[i]); |
6f8aaf68 | 114 | for (aut = autoloads; aut; aut = aut->next) |
75eb7d11 | 115 | if (grub_strcmp (args[i], aut->name) == 0 |
ca8c0baf VS |
116 | || (grub_strcmp (args[i], "ofconsole") == 0 |
117 | && grub_strcmp ("console", aut->name) == 0) | |
75eb7d11 VS |
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)) | |
6f8aaf68 VS |
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 | } | |
d745dda7 VS |
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 | } | |
6f8aaf68 | 137 | if (!aut) |
d61386e2 VS |
138 | return grub_error (GRUB_ERR_BAD_ARGUMENT, |
139 | N_("terminal `%s' isn't found"), | |
6f8aaf68 VS |
140 | args[i]); |
141 | again = 1; | |
142 | } | |
0aa63398 VS |
143 | } |
144 | ||
145 | if (grub_strcmp (args[0], "--append") == 0) | |
146 | { | |
147 | for (i = 1; i < argc; i++) | |
6f8aaf68 VS |
148 | { |
149 | for (term = *disabled; term; term = term->next) | |
ca8c0baf VS |
150 | if (grub_strcmp (args[i], term->name) == 0 |
151 | || (grub_strcmp (args[i], "ofconsole") == 0 | |
152 | && grub_strcmp ("console", term->name) == 0)) | |
6f8aaf68 VS |
153 | break; |
154 | if (term) | |
155 | { | |
58664b94 | 156 | if (term->init && term->init (term) != GRUB_ERR_NONE) |
cba98e8d RM |
157 | return grub_errno; |
158 | ||
87edb894 | 159 | grub_list_remove (GRUB_AS_LIST (term)); |
6f8aaf68 VS |
160 | grub_list_push (GRUB_AS_LIST_P (enabled), GRUB_AS_LIST (term)); |
161 | } | |
162 | } | |
0aa63398 VS |
163 | return GRUB_ERR_NONE; |
164 | } | |
165 | ||
166 | if (grub_strcmp (args[0], "--remove") == 0) | |
167 | { | |
168 | for (i = 1; i < argc; i++) | |
6f8aaf68 VS |
169 | { |
170 | for (term = *enabled; term; term = term->next) | |
ca8c0baf VS |
171 | if (grub_strcmp (args[i], term->name) == 0 |
172 | || (grub_strcmp (args[i], "ofconsole") == 0 | |
173 | && grub_strcmp ("console", term->name) == 0)) | |
6f8aaf68 VS |
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"); | |
87edb894 | 180 | grub_list_remove (GRUB_AS_LIST (term)); |
6f8aaf68 | 181 | if (term->fini) |
58664b94 | 182 | term->fini (term); |
6f8aaf68 VS |
183 | grub_list_push (GRUB_AS_LIST_P (disabled), GRUB_AS_LIST (term)); |
184 | } | |
185 | } | |
0aa63398 VS |
186 | return GRUB_ERR_NONE; |
187 | } | |
188 | for (i = 0; i < argc; i++) | |
189 | { | |
6f8aaf68 | 190 | for (term = *disabled; term; term = term->next) |
ca8c0baf VS |
191 | if (grub_strcmp (args[i], term->name) == 0 |
192 | || (grub_strcmp (args[i], "ofconsole") == 0 | |
193 | && grub_strcmp ("console", term->name) == 0)) | |
6f8aaf68 | 194 | break; |
0aa63398 | 195 | if (term) |
6f8aaf68 | 196 | { |
58664b94 | 197 | if (term->init && term->init (term) != GRUB_ERR_NONE) |
6f8aaf68 | 198 | return grub_errno; |
cba98e8d | 199 | |
87edb894 | 200 | grub_list_remove (GRUB_AS_LIST (term)); |
6f8aaf68 VS |
201 | grub_list_push (GRUB_AS_LIST_P (enabled), GRUB_AS_LIST (term)); |
202 | } | |
0aa63398 | 203 | } |
6f8aaf68 | 204 | |
0aa63398 | 205 | { |
6f8aaf68 VS |
206 | struct abstract_terminal *next; |
207 | for (term = *enabled; term; term = next) | |
0aa63398 | 208 | { |
6f8aaf68 VS |
209 | next = term->next; |
210 | for (i = 0; i < argc; i++) | |
ca8c0baf VS |
211 | if (grub_strcmp (args[i], term->name) == 0 |
212 | || (grub_strcmp (args[i], "ofconsole") == 0 | |
213 | && grub_strcmp ("console", term->name) == 0)) | |
6f8aaf68 VS |
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"); | |
87edb894 | 220 | grub_list_remove (GRUB_AS_LIST (term)); |
6f8aaf68 | 221 | if (term->fini) |
58664b94 | 222 | term->fini (term); |
6f8aaf68 VS |
223 | grub_list_push (GRUB_AS_LIST_P (disabled), GRUB_AS_LIST (term)); |
224 | } | |
0aa63398 VS |
225 | } |
226 | } | |
227 | ||
228 | return GRUB_ERR_NONE; | |
229 | } | |
230 | ||
d8a1cbbd | 231 | static grub_err_t |
6f8aaf68 | 232 | grub_cmd_terminal_input (grub_command_t cmd __attribute__ ((unused)), |
0aa63398 VS |
233 | int argc, char **args) |
234 | { | |
6f8aaf68 | 235 | (void) GRUB_FIELD_MATCH (grub_term_inputs, struct abstract_terminal *, next); |
87edb894 | 236 | (void) GRUB_FIELD_MATCH (grub_term_inputs, struct abstract_terminal *, prev); |
6f8aaf68 VS |
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, | |
fc836af9 VS |
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:")); | |
6f8aaf68 | 246 | } |
0aa63398 | 247 | |
6f8aaf68 VS |
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); | |
87edb894 | 253 | (void) GRUB_FIELD_MATCH (grub_term_outputs, struct abstract_terminal *, prev); |
6f8aaf68 VS |
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); | |
fc836af9 VS |
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:")); | |
0aa63398 VS |
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, | |
d8b5cd40 VS |
271 | N_("[--append|--remove] " |
272 | "[TERMINAL1] [TERMINAL2] ..."), | |
273 | N_("List or select an input terminal.")); | |
0aa63398 VS |
274 | cmd_terminal_output = |
275 | grub_register_command ("terminal_output", grub_cmd_terminal_output, | |
d8b5cd40 VS |
276 | N_("[--append|--remove] " |
277 | "[TERMINAL1] [TERMINAL2] ..."), | |
278 | N_("List or select an output terminal.")); | |
0aa63398 VS |
279 | } |
280 | ||
281 | GRUB_MOD_FINI(terminal) | |
282 | { | |
283 | grub_unregister_command (cmd_terminal_input); | |
284 | grub_unregister_command (cmd_terminal_output); | |
285 | } |