]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/kern/env.c
1.1.07 release
[Ventoy.git] / GRUB2 / MOD_SRC / grub-2.04 / grub-core / kern / env.c
1 /* env.c - Environment variables */
2 /*
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2003,2005,2006,2007,2008,2009 Free Software Foundation, Inc.
5 *
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <grub/env.h>
21 #include <grub/env_private.h>
22 #include <grub/misc.h>
23 #include <grub/mm.h>
24
25 /* The initial context. */
26 static struct grub_env_context initial_context;
27
28 /* The current context. */
29 struct grub_env_context *grub_current_context = &initial_context;
30
31 static grub_env_read_hook_t vtoy_menu_lang_read_hook;
32
33 /* Return the hash representation of the string S. */
34 static unsigned int
35 grub_env_hashval (const char *s)
36 {
37 unsigned int i = 0;
38
39 /* XXX: This can be done much more efficiently. */
40 while (*s)
41 i += 5 * *(s++);
42
43 return i % HASHSZ;
44 }
45
46 static struct grub_env_var *
47 grub_env_find (const char *name)
48 {
49 struct grub_env_var *var;
50 int idx = grub_env_hashval (name);
51
52 /* Look for the variable in the current context. */
53 for (var = grub_current_context->vars[idx]; var; var = var->next)
54 if (grub_strcmp (var->name, name) == 0)
55 return var;
56
57 return 0;
58 }
59
60 static void
61 grub_env_insert (struct grub_env_context *context,
62 struct grub_env_var *var)
63 {
64 int idx = grub_env_hashval (var->name);
65
66 /* Insert the variable into the hashtable. */
67 var->prevp = &context->vars[idx];
68 var->next = context->vars[idx];
69 if (var->next)
70 var->next->prevp = &(var->next);
71 context->vars[idx] = var;
72 }
73
74 static void
75 grub_env_remove (struct grub_env_var *var)
76 {
77 /* Remove the entry from the variable table. */
78 *var->prevp = var->next;
79 if (var->next)
80 var->next->prevp = var->prevp;
81 }
82
83 grub_err_t
84 grub_env_set (const char *name, const char *val)
85 {
86 struct grub_env_var *var;
87
88 /* If the variable does already exist, just update the variable. */
89 var = grub_env_find (name);
90 if (var)
91 {
92 char *old = var->value;
93
94 if (var->write_hook)
95 var->value = var->write_hook (var, val);
96 else
97 var->value = grub_strdup (val);
98
99 if (! var->value)
100 {
101 var->value = old;
102 return grub_errno;
103 }
104
105 grub_free (old);
106 return GRUB_ERR_NONE;
107 }
108
109 /* The variable does not exist, so create a new one. */
110 var = grub_zalloc (sizeof (*var));
111 if (! var)
112 return grub_errno;
113
114 var->name = grub_strdup (name);
115 if (! var->name)
116 goto fail;
117
118 var->value = grub_strdup (val);
119 if (! var->value)
120 goto fail;
121
122 grub_env_insert (grub_current_context, var);
123
124 return GRUB_ERR_NONE;
125
126 fail:
127 grub_free (var->name);
128 grub_free (var->value);
129 grub_free (var);
130
131 return grub_errno;
132 }
133
134 const char *
135 grub_env_get (const char *name)
136 {
137 struct grub_env_var *var;
138
139 if (name && vtoy_menu_lang_read_hook && grub_strncmp(name, "VTLANG_", 7) == 0)
140 return vtoy_menu_lang_read_hook(NULL, name);
141
142 var = grub_env_find (name);
143 if (! var)
144 return 0;
145
146 if (var->read_hook)
147 return var->read_hook (var, var->value);
148
149 return var->value;
150 }
151
152 void
153 grub_env_unset (const char *name)
154 {
155 struct grub_env_var *var;
156
157 var = grub_env_find (name);
158 if (! var)
159 return;
160
161 if (var->read_hook || var->write_hook)
162 {
163 grub_env_set (name, "");
164 return;
165 }
166
167 grub_env_remove (var);
168
169 grub_free (var->name);
170 grub_free (var->value);
171 grub_free (var);
172 }
173
174 struct grub_env_var *
175 grub_env_update_get_sorted (void)
176 {
177 struct grub_env_var *sorted_list = 0;
178 int i;
179
180 /* Add variables associated with this context into a sorted list. */
181 for (i = 0; i < HASHSZ; i++)
182 {
183 struct grub_env_var *var;
184
185 for (var = grub_current_context->vars[i]; var; var = var->next)
186 {
187 struct grub_env_var *p, **q;
188
189 for (q = &sorted_list, p = *q; p; q = &((*q)->sorted_next), p = *q)
190 {
191 if (grub_strcmp (p->name, var->name) > 0)
192 break;
193 }
194
195 var->sorted_next = *q;
196 *q = var;
197 }
198 }
199
200 return sorted_list;
201 }
202
203 grub_err_t
204 grub_register_variable_hook (const char *name,
205 grub_env_read_hook_t read_hook,
206 grub_env_write_hook_t write_hook)
207 {
208 struct grub_env_var *var = grub_env_find (name);
209
210 if (! var)
211 {
212 if (grub_env_set (name, "") != GRUB_ERR_NONE)
213 return grub_errno;
214
215 var = grub_env_find (name);
216 /* XXX Insert an assertion? */
217 }
218
219 var->read_hook = read_hook;
220 var->write_hook = write_hook;
221
222 return GRUB_ERR_NONE;
223 }
224
225 grub_err_t
226 grub_register_vtoy_menu_lang_hook(grub_env_read_hook_t read_hook)
227 {
228 vtoy_menu_lang_read_hook = read_hook;
229 return GRUB_ERR_NONE;
230 }
231
232 grub_err_t
233 grub_env_export (const char *name)
234 {
235 struct grub_env_var *var;
236
237 var = grub_env_find (name);
238 if (! var)
239 {
240 grub_err_t err;
241
242 err = grub_env_set (name, "");
243 if (err)
244 return err;
245 var = grub_env_find (name);
246 }
247 var->global = 1;
248
249 return GRUB_ERR_NONE;
250 }