context.c 4.43 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
/* env.c - Environment variables */
/*
 *  GRUB  --  GRand Unified Bootloader
 *  Copyright (C) 2003,2005,2006,2007,2008,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/env.h>
#include <grub/env_private.h>
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/command.h>
25
#include <grub/normal.h>
26
#include <grub/i18n.h>
27 28 29 30 31 32 33

struct menu_pointer
{
  grub_menu_t menu;
  struct menu_pointer *prev;
};

34 35
static struct menu_pointer initial_menu;
static struct menu_pointer *current_menu = &initial_menu;
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54

void
grub_env_unset_menu (void)
{
  current_menu->menu = NULL;
}

grub_menu_t
grub_env_get_menu (void)
{
  return current_menu->menu;
}

void
grub_env_set_menu (grub_menu_t nmenu)
{
  current_menu->menu = nmenu;
}

55 56
static grub_err_t
grub_env_new_context (int export_all)
57 58 59 60 61 62 63 64 65 66
{
  struct grub_env_context *context;
  int i;
  struct menu_pointer *menu;

  context = grub_zalloc (sizeof (*context));
  if (! context)
    return grub_errno;
  menu = grub_zalloc (sizeof (*menu));
  if (! menu)
67 68 69 70
    {
      grub_free (context);
      return grub_errno;
    }
71 72 73 74 75 76 77 78 79 80 81 82 83

  context->prev = grub_current_context;
  grub_current_context = context;

  menu->prev = current_menu;
  current_menu = menu;

  /* Copy exported variables.  */
  for (i = 0; i < HASHSZ; i++)
    {
      struct grub_env_var *var;

      for (var = context->prev->vars[i]; var; var = var->next)
84 85 86 87 88 89 90 91 92 93
	if (var->global || export_all)
	  {
	    if (grub_env_set (var->name, var->value) != GRUB_ERR_NONE)
	      {
		grub_env_context_close ();
		return grub_errno;
	      }
	    grub_env_export (var->name);
	    grub_register_variable_hook (var->name, var->read_hook, var->write_hook);
	  }
94 95 96 97 98
    }

  return GRUB_ERR_NONE;
}

99 100 101 102 103 104
grub_err_t
grub_env_context_open (void)
{
  return grub_env_new_context (0);
}

105
int grub_extractor_level = 0;
106 107

grub_err_t
108
grub_env_extractor_open (int source)
109
{
110
  grub_extractor_level++;
111 112 113
  return grub_env_new_context (source);
}

114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
grub_err_t
grub_env_context_close (void)
{
  struct grub_env_context *context;
  int i;
  struct menu_pointer *menu;

  if (! grub_current_context->prev)
    return grub_error (GRUB_ERR_BAD_ARGUMENT,
		       "cannot close the initial context");

  /* Free the variables associated with this context.  */
  for (i = 0; i < HASHSZ; i++)
    {
      struct grub_env_var *p, *q;

      for (p = grub_current_context->vars[i]; p; p = q)
	{
	  q = p->next;
          grub_free (p->name);
	  grub_free (p->value);
	  grub_free (p);
	}
    }

  /* Restore the previous context.  */
  context = grub_current_context->prev;
  grub_free (grub_current_context);
  grub_current_context = context;

  menu = current_menu->prev;
145 146
  if (current_menu->menu)
    grub_normal_free_menu (current_menu->menu);
147 148 149 150 151 152
  grub_free (current_menu);
  current_menu = menu;

  return GRUB_ERR_NONE;
}

153
grub_err_t
154
grub_env_extractor_close (int source)
155
{
156
  grub_menu_t menu = NULL;
157 158 159 160 161 162 163 164 165 166
  grub_menu_entry_t *last;
  grub_err_t err;

  if (source)
    {
      menu = grub_env_get_menu ();
      grub_env_unset_menu ();
    }
  err = grub_env_context_close ();

167
  if (source && menu)
168
    {
169
      grub_menu_t menu2;
170 171 172 173 174 175 176 177 178 179
      menu2 = grub_env_get_menu ();
      
      last = &menu2->entry_list;
      while (*last)
	last = &(*last)->next;
      
      *last = menu->entry_list;
      menu2->size += menu->size;
    }

180
  grub_extractor_level--;
181 182 183
  return err;
}

184 185 186 187 188 189
static grub_command_t export_cmd;

static grub_err_t
grub_cmd_export (struct grub_command *cmd __attribute__ ((unused)),
		 int argc, char **args)
{
190 191
  int i;

192 193
  if (argc < 1)
    return grub_error (GRUB_ERR_BAD_ARGUMENT,
194
		       N_("one argument expected"));
195

196 197 198
  for (i = 0; i < argc; i++)
    grub_env_export (args[i]);

199 200 201 202 203 204 205
  return 0;
}

void
grub_context_init (void)
{
  export_cmd = grub_register_command ("export", grub_cmd_export,
BVK Chaitanya's avatar
BVK Chaitanya committed
206
				      N_("ENVVAR [ENVVAR] ..."),
207
				      N_("Export variables."));
208 209 210 211 212 213 214
}

void
grub_context_fini (void)
{
  grub_unregister_command (export_cmd);
}