dyncmd.c 4.22 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/* dyncmd.c - support dynamic command */
/*
 *  GRUB  --  GRand Unified Bootloader
 *  Copyright (C) 2009  Free Software Foundation, Inc.
 *
 *  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/dl.h>
#include <grub/mm.h>
#include <grub/env.h>
#include <grub/misc.h>
#include <grub/command.h>
#include <grub/normal.h>
26 27
#include <grub/extcmd.h>
#include <grub/script_sh.h>
28
#include <grub/i18n.h>
29

30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
grub_command_t
grub_dyncmd_get_cmd (grub_command_t cmd)
{
  grub_extcmd_t extcmd = cmd->data;
  char *modname;
  char *name;
  grub_dl_t mod;

  modname = extcmd->data;
  mod = grub_dl_load (modname);
  if (!mod)
    return NULL;

  grub_free (modname);
  grub_dl_ref (mod);

  name = (char *) cmd->name;
  grub_unregister_extcmd (extcmd);

  cmd = grub_command_find (name);

  grub_free (name);

  return cmd;
}

56
static grub_err_t
57
grub_dyncmd_dispatcher (struct grub_extcmd_context *ctxt,
58 59
			int argc, char **args)
{
60
  char *modname;
61 62
  grub_dl_t mod;
  grub_err_t ret;
63 64
  grub_extcmd_t extcmd = ctxt->extcmd;
  grub_command_t cmd = extcmd->cmd;
65
  char *name;
66

67
  modname = extcmd->data;
68
  mod = grub_dl_load (modname);
69 70 71 72 73 74 75 76 77 78 79
  if (!mod)
    return grub_errno;

  grub_free (modname);
  grub_dl_ref (mod);

  name = (char *) cmd->name;
  grub_unregister_extcmd (extcmd);

  cmd = grub_command_find (name);
  if (cmd)
80
    {
81 82 83
      if (cmd->flags & GRUB_COMMAND_FLAG_BLOCKS &&
	  cmd->flags & GRUB_COMMAND_FLAG_EXTCMD)
	ret = grub_extcmd_dispatcher (cmd, argc, args, ctxt->script);
84
      else
85
	ret = (cmd->func) (cmd, argc, args);
86 87 88 89
    }
  else
    ret = grub_errno;

90 91
  grub_free (name);

92 93 94 95 96
  return ret;
}

/* Read the file command.lst for auto-loading.  */
void
97
read_command_list (const char *prefix)
98 99 100 101 102
{
  if (prefix)
    {
      char *filename;

103 104
      filename = grub_xasprintf ("%s/" GRUB_TARGET_CPU "-" GRUB_PLATFORM
				 "/command.lst", prefix);
105 106 107 108 109 110 111
      if (filename)
	{
	  grub_file_t file;

	  file = grub_file_open (filename);
	  if (file)
	    {
112
	      char *buf = NULL;
113
	      grub_command_t ptr, last = 0, next;
114 115

	      /* Override previous commands.lst.  */
116
	      for (ptr = grub_command_list; ptr; ptr = next)
117
		{
118
		  next = ptr->next;
119
		  if (ptr->flags & GRUB_COMMAND_FLAG_DYNCMD)
120 121 122 123 124
		    {
		      if (last)
			last->next = ptr->next;
		      else
			grub_command_list = ptr->next;
125
		      grub_free (ptr->data); /* extcmd struct */
126
		      grub_free (ptr);
127 128 129
		    }
		  else
		    last = ptr;
130 131
		}

132
	      for (;; grub_free (buf))
133 134
		{
		  char *p, *name, *modname;
135
		  grub_extcmd_t cmd;
136 137 138 139 140 141 142 143
		  int prio = 0;

		  buf = grub_file_getline (file);

		  if (! buf)
		    break;

		  name = buf;
144 145 146
		  while (grub_isspace (name[0]))
		    name++;

147 148 149 150 151 152 153 154 155 156 157 158 159 160
		  if (*name == '*')
		    {
		      name++;
		      prio++;
		    }

		  if (! grub_isgraph (name[0]))
		    continue;

		  p = grub_strchr (name, ':');
		  if (! p)
		    continue;

		  *p = '\0';
161 162 163
		  p++;
		  while (*p == ' ' || *p == '\t')
		    p++;
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181

		  if (! grub_isgraph (*p))
		    continue;

		  if (grub_dl_get (p))
		    continue;

		  name = grub_strdup (name);
		  if (! name)
		    continue;

		  modname = grub_strdup (p);
		  if (! modname)
		    {
		      grub_free (name);
		      continue;
		    }

182 183 184 185 186
		  cmd = grub_register_extcmd_prio (name,
						   grub_dyncmd_dispatcher,
						   GRUB_COMMAND_FLAG_BLOCKS
						   | GRUB_COMMAND_FLAG_EXTCMD
						   | GRUB_COMMAND_FLAG_DYNCMD,
187 188
						   0, N_("module isn't loaded"),
						   0, prio);
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
		  if (! cmd)
		    {
		      grub_free (name);
		      grub_free (modname);
		      continue;
		    }
		  cmd->data = modname;

		  /* Update the active flag.  */
		  grub_command_find (name);
		}

	      grub_file_close (file);
	    }

	  grub_free (filename);
	}
    }

  /* Ignore errors.  */
  grub_errno = GRUB_ERR_NONE;
}