terminal.c 9.5 KB
Newer Older
1 2
/*
 *  GRUB  --  GRand Unified Bootloader
3
 *  Copyright (C) 2009,2010  Free Software Foundation, Inc.
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
 *
 *  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/mm.h>
#include <grub/dl.h>
#include <grub/command.h>
#include <grub/term.h>
#include <grub/i18n.h>
#include <grub/misc.h>

26 27
GRUB_MOD_LICENSE ("GPLv3+");

28 29 30
struct grub_term_autoload *grub_term_input_autoload = NULL;
struct grub_term_autoload *grub_term_output_autoload = NULL;

31 32 33
struct abstract_terminal
{
  struct abstract_terminal *next;
34
  struct abstract_terminal *prev;
35
  const char *name;
36 37
  grub_err_t (*init) (struct abstract_terminal *term);
  grub_err_t (*fini) (struct abstract_terminal *term);
38 39
};

40
static grub_err_t
41 42 43 44 45
handle_command (int argc, char **args, struct abstract_terminal **enabled,
               struct abstract_terminal **disabled,
               struct grub_term_autoload *autoloads,
               const char *active_str,
               const char *available_str)
46 47
{
  int i;
48
  struct abstract_terminal *term;
49
  struct grub_term_autoload *aut;
50 51 52

  if (argc == 0)
    {
53 54 55
      grub_puts_ (active_str);
      for (term = *enabled; term; term = term->next)
       grub_printf ("%s ", term->name);
56
      grub_printf ("\n");
57 58 59
      grub_puts_ (available_str);
      for (term = *disabled; term; term = term->next)
       grub_printf ("%s ", term->name);
60
      /* This is quadratic but we don't expect mode than 30 terminal
61 62 63 64
        modules ever.  */
      for (aut = autoloads; aut; aut = aut->next)
       {
         for (term = *disabled; term; term = term->next)
65 66 67 68
           if (grub_strcmp (term->name, aut->name) == 0
	       || (aut->name[0] && aut->name[grub_strlen (aut->name) - 1] == '*'
		   && grub_memcmp (term->name, aut->name,
				   grub_strlen (aut->name) - 1) == 0))
69 70 71
             break;
         if (!term)
           for (term = *enabled; term; term = term->next)
72 73 74 75
             if (grub_strcmp (term->name, aut->name) == 0
		 || (aut->name[0] && aut->name[grub_strlen (aut->name) - 1] == '*'
		     && grub_memcmp (term->name, aut->name,
				     grub_strlen (aut->name) - 1) == 0))
76 77 78 79
               break;
         if (!term)
           grub_printf ("%s ", aut->name);
       }
80 81 82 83 84 85
      grub_printf ("\n");
      return GRUB_ERR_NONE;
    }
  i = 0;

  if (grub_strcmp (args[0], "--append") == 0
86
      || grub_strcmp (args[0], "--remove") == 0)
87 88 89 90 91 92 93
    i++;

  if (i == argc)
    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_ ("no terminal specified"));

  for (; i < argc; i++)
    {
94 95
      int again = 0;
      while (1)
96 97
       {
         for (term = *disabled; term; term = term->next)
98 99 100
           if (grub_strcmp (args[i], term->name) == 0
	       || (grub_strcmp (args[i], "ofconsole") == 0
		   && grub_strcmp ("console", term->name) == 0))
101 102 103
             break;
         if (term == 0)
           for (term = *enabled; term; term = term->next)
104 105 106
             if (grub_strcmp (args[i], term->name) == 0
		 || (grub_strcmp (args[i], "ofconsole") == 0
		     && grub_strcmp ("console", term->name) == 0))
107 108 109 110
               break;
         if (term)
           break;
         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 117
	       || (grub_strcmp (args[i], "ofconsole") == 0
		   && grub_strcmp ("console", aut->name) == 0)
118 119 120
	       || (aut->name[0] && aut->name[grub_strlen (aut->name) - 1] == '*'
		   && grub_memcmp (args[i], aut->name,
				   grub_strlen (aut->name) - 1) == 0))
121 122 123 124 125 126 127 128
             {
               grub_dl_t mod;
               mod = grub_dl_load (aut->modname);
               if (mod)
                 grub_dl_ref (mod);
               grub_errno = GRUB_ERR_NONE;
               break;
             }
129 130 131 132 133 134 135 136
	 if (grub_memcmp (args[i], "serial_usb",
				  sizeof ("serial_usb") - 1) == 0
	     && grub_term_poll_usb)
	   {
	     grub_term_poll_usb (1);
	     again = 1;
	     continue;
	   }
137
         if (!aut)
138 139
           return grub_error (GRUB_ERR_BAD_ARGUMENT,
			      N_("terminal `%s' isn't found"),
140 141 142
                              args[i]);
         again = 1;
       }
143 144 145 146 147
    }

  if (grub_strcmp (args[0], "--append") == 0)
    {
      for (i = 1; i < argc; i++)
148 149
       {
         for (term = *disabled; term; term = term->next)
150 151 152
           if (grub_strcmp (args[i], term->name) == 0
	       || (grub_strcmp (args[i], "ofconsole") == 0
		   && grub_strcmp ("console", term->name) == 0))
153 154 155
             break;
         if (term)
           {
156
              if (term->init && term->init (term) != GRUB_ERR_NONE)
157 158
                return grub_errno;

159
             grub_list_remove (GRUB_AS_LIST (term));
160 161 162
             grub_list_push (GRUB_AS_LIST_P (enabled), GRUB_AS_LIST (term));
           }
       }
163 164 165 166 167 168
      return GRUB_ERR_NONE;
    }

  if (grub_strcmp (args[0], "--remove") == 0)
    {
      for (i = 1; i < argc; i++)
169 170
       {
         for (term = *enabled; term; term = term->next)
171 172 173
           if (grub_strcmp (args[i], term->name) == 0
	       || (grub_strcmp (args[i], "ofconsole") == 0
		   && grub_strcmp ("console", term->name) == 0))
174 175 176 177 178 179
             break;
         if (term)
           {
             if (!term->next && term == *enabled)
               return grub_error (GRUB_ERR_BAD_ARGUMENT,
                                  "can't remove the last terminal");
180
             grub_list_remove (GRUB_AS_LIST (term));
181
             if (term->fini)
182
               term->fini (term);
183 184 185
             grub_list_push (GRUB_AS_LIST_P (disabled), GRUB_AS_LIST (term));
           }
       }
186 187 188 189
      return GRUB_ERR_NONE;
    }
  for (i = 0; i < argc; i++)
    {
190
      for (term = *disabled; term; term = term->next)
191 192 193
       if (grub_strcmp (args[i], term->name) == 0
	   || (grub_strcmp (args[i], "ofconsole") == 0
	       && 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 202
         grub_list_push (GRUB_AS_LIST_P (enabled), GRUB_AS_LIST (term));
       }       
203
    }
204
  
205
  {
206 207
    struct abstract_terminal *next;
    for (term = *enabled; term; term = next)
208
      {
209 210
       next = term->next;
       for (i = 0; i < argc; i++)
211 212 213
         if (grub_strcmp (args[i], term->name) == 0
	     || (grub_strcmp (args[i], "ofconsole") == 0
		 && grub_strcmp ("console", term->name) == 0))
214 215 216 217 218 219
           break;
       if (i == argc)
         {
           if (!term->next && term == *enabled)
             return grub_error (GRUB_ERR_BAD_ARGUMENT,
                                "can't remove the last terminal");
220
           grub_list_remove (GRUB_AS_LIST (term));
221
           if (term->fini)
222
             term->fini (term);
223 224
           grub_list_push (GRUB_AS_LIST_P (disabled), GRUB_AS_LIST (term));
         }
225 226 227 228 229 230
      }
  }

  return GRUB_ERR_NONE;
}

231
static grub_err_t
232
grub_cmd_terminal_input (grub_command_t cmd __attribute__ ((unused)),
233 234
			 int argc, char **args)
{
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 238 239 240
  (void) GRUB_FIELD_MATCH (grub_term_inputs, struct abstract_terminal *, name);
  (void) GRUB_FIELD_MATCH (grub_term_inputs, struct abstract_terminal *, init);
  (void) GRUB_FIELD_MATCH (grub_term_inputs, struct abstract_terminal *, fini);
  return handle_command (argc, args,
241 242 243 244 245
			 (struct abstract_terminal **) (void *) &grub_term_inputs,
			 (struct abstract_terminal **) (void *) &grub_term_inputs_disabled,
			 grub_term_input_autoload,
			 N_ ("Active input terminals:"),
			 N_ ("Available input terminals:"));
246
}
247

248 249 250 251 252
static grub_err_t
grub_cmd_terminal_output (grub_command_t cmd __attribute__ ((unused)),
                         int argc, char **args)
{
  (void) GRUB_FIELD_MATCH (grub_term_outputs, struct abstract_terminal *, next);
253
  (void) GRUB_FIELD_MATCH (grub_term_outputs, struct abstract_terminal *, prev);
254 255 256
  (void) GRUB_FIELD_MATCH (grub_term_outputs, struct abstract_terminal *, name);
  (void) GRUB_FIELD_MATCH (grub_term_outputs, struct abstract_terminal *, init);
  (void) GRUB_FIELD_MATCH (grub_term_outputs, struct abstract_terminal *, fini);
257 258 259 260 261 262
  return handle_command (argc, args,
			 (struct abstract_terminal **) (void *) &grub_term_outputs,
			 (struct abstract_terminal **) (void *) &grub_term_outputs_disabled,
			 grub_term_output_autoload,
			 N_ ("Active output terminals:"),
			 N_ ("Available output terminals:"));
263 264 265 266 267 268 269 270
}

static grub_command_t cmd_terminal_input, cmd_terminal_output;

GRUB_MOD_INIT(terminal)
{
  cmd_terminal_input =
    grub_register_command ("terminal_input", grub_cmd_terminal_input,
271 272 273
			   N_("[--append|--remove] "
			      "[TERMINAL1] [TERMINAL2] ..."),
			   N_("List or select an input terminal."));
274 275
  cmd_terminal_output =
    grub_register_command ("terminal_output", grub_cmd_terminal_output,
276 277 278
			   N_("[--append|--remove] "
			      "[TERMINAL1] [TERMINAL2] ..."),
			   N_("List or select an output terminal."));
279 280 281 282 283 284 285
}

GRUB_MOD_FINI(terminal)
{
  grub_unregister_command (cmd_terminal_input);
  grub_unregister_command (cmd_terminal_output);
}