~ubuntu-branches/ubuntu/trusty/grub2/trusty-updates

« back to all changes in this revision

Viewing changes to grub-core/lib/envblk.c

Tags: upstream-1.99~20101122
ImportĀ upstreamĀ versionĀ 1.99~20101122

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* envblk.c - Common functions for environment block.  */
 
2
/*
 
3
 *  GRUB  --  GRand Unified Bootloader
 
4
 *  Copyright (C) 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 <config.h>
 
21
#include <grub/types.h>
 
22
#include <grub/misc.h>
 
23
#include <grub/mm.h>
 
24
#include <grub/lib/envblk.h>
 
25
 
 
26
grub_envblk_t
 
27
grub_envblk_open (char *buf, grub_size_t size)
 
28
{
 
29
  grub_envblk_t envblk;
 
30
 
 
31
  if (size < sizeof (GRUB_ENVBLK_SIGNATURE)
 
32
      || grub_memcmp (buf, GRUB_ENVBLK_SIGNATURE,
 
33
                      sizeof (GRUB_ENVBLK_SIGNATURE) - 1))
 
34
    {
 
35
      grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid environment block");
 
36
      return 0;
 
37
    }
 
38
 
 
39
  envblk = grub_malloc (sizeof (*envblk));
 
40
  if (envblk)
 
41
    {
 
42
      envblk->buf = buf;
 
43
      envblk->size = size;
 
44
    }
 
45
 
 
46
  return envblk;
 
47
}
 
48
 
 
49
void
 
50
grub_envblk_close (grub_envblk_t envblk)
 
51
{
 
52
  grub_free (envblk->buf);
 
53
  grub_free (envblk);
 
54
}
 
55
 
 
56
static int
 
57
escaped_value_len (const char *value)
 
58
{
 
59
  int n = 0;
 
60
  char *p;
 
61
 
 
62
  for (p = (char *) value; *p; p++)
 
63
    {
 
64
      if (*p == '\\' || *p == '\n')
 
65
        n += 2;
 
66
      else
 
67
        n++;
 
68
    }
 
69
 
 
70
  return n;
 
71
}
 
72
 
 
73
static char *
 
74
find_next_line (char *p, const char *pend)
 
75
{
 
76
  while (p < pend)
 
77
    {
 
78
      if (*p == '\\')
 
79
        p += 2;
 
80
      else if (*p == '\n')
 
81
        break;
 
82
      else
 
83
        p++;
 
84
    }
 
85
 
 
86
  return p + 1;
 
87
}
 
88
 
 
89
int
 
90
grub_envblk_set (grub_envblk_t envblk, const char *name, const char *value)
 
91
{
 
92
  char *p, *pend;
 
93
  char *space;
 
94
  int found = 0;
 
95
  int nl;
 
96
  int vl;
 
97
  int i;
 
98
 
 
99
  nl = grub_strlen (name);
 
100
  vl = escaped_value_len (value);
 
101
  p = envblk->buf + sizeof (GRUB_ENVBLK_SIGNATURE) - 1;
 
102
  pend = envblk->buf + envblk->size;
 
103
 
 
104
  /* First, look at free space.  */
 
105
  for (space = pend - 1; *space == '#'; space--)
 
106
    ;
 
107
 
 
108
  if (*space != '\n')
 
109
    /* Broken.  */
 
110
    return 0;
 
111
 
 
112
  space++;
 
113
 
 
114
  while (p + nl + 1 < space)
 
115
    {
 
116
      if (grub_memcmp (p, name, nl) == 0 && p[nl] == '=')
 
117
        {
 
118
          int len;
 
119
 
 
120
          /* Found the same name.  */
 
121
          p += nl + 1;
 
122
 
 
123
          /* Check the length of the current value.  */
 
124
          len = 0;
 
125
          while (p + len < pend && p[len] != '\n')
 
126
            {
 
127
              if (p[len] == '\\')
 
128
                len += 2;
 
129
              else
 
130
                len++;
 
131
            }
 
132
 
 
133
          if (p + len >= pend)
 
134
            /* Broken.  */
 
135
            return 0;
 
136
 
 
137
          if (pend - space < vl - len)
 
138
            /* No space.  */
 
139
            return 0;
 
140
 
 
141
          if (vl < len)
 
142
            {
 
143
              /* Move the following characters backward, and fill the new
 
144
                 space with harmless characters.  */
 
145
              grub_memmove (p + vl, p + len, pend - (p + len));
 
146
              grub_memset (space + len - vl, '#', len - vl);
 
147
            }
 
148
          else
 
149
            /* Move the following characters forward.  */
 
150
            grub_memmove (p + vl, p + len, pend - (p + vl));
 
151
 
 
152
          found = 1;
 
153
          break;
 
154
        }
 
155
 
 
156
      p = find_next_line (p, pend);
 
157
    }
 
158
 
 
159
  if (! found)
 
160
    {
 
161
      /* Append a new variable.  */
 
162
 
 
163
      if (pend - space < nl + 1 + vl + 1)
 
164
        /* No space.  */
 
165
        return 0;
 
166
 
 
167
      grub_memcpy (space, name, nl);
 
168
      p = space + nl;
 
169
      *p++ = '=';
 
170
    }
 
171
 
 
172
  /* Write the value.  */
 
173
  for (i = 0; value[i]; i++)
 
174
    {
 
175
      if (value[i] == '\\' || value[i] == '\n')
 
176
        *p++ = '\\';
 
177
 
 
178
      *p++ = value[i];
 
179
    }
 
180
 
 
181
  *p = '\n';
 
182
  return 1;
 
183
}
 
184
 
 
185
void
 
186
grub_envblk_delete (grub_envblk_t envblk, const char *name)
 
187
{
 
188
  char *p, *pend;
 
189
  int nl;
 
190
 
 
191
  nl = grub_strlen (name);
 
192
  p = envblk->buf + sizeof (GRUB_ENVBLK_SIGNATURE) - 1;
 
193
  pend = envblk->buf + envblk->size;
 
194
 
 
195
  while (p + nl + 1 < pend)
 
196
    {
 
197
      if (grub_memcmp (p, name, nl) == 0 && p[nl] == '=')
 
198
        {
 
199
          /* Found.  */
 
200
          int len = nl + 1;
 
201
 
 
202
          while (p + len < pend)
 
203
            {
 
204
              if (p[len] == '\n')
 
205
                break;
 
206
              else if (p[len] == '\\')
 
207
                len += 2;
 
208
              else
 
209
                len++;
 
210
            }
 
211
 
 
212
          if (p + len >= pend)
 
213
            /* Broken.  */
 
214
            return;
 
215
 
 
216
          len++;
 
217
          grub_memmove (p, p + len, pend - (p + len));
 
218
          grub_memset (pend - len, '#', len);
 
219
          break;
 
220
        }
 
221
 
 
222
      p = find_next_line (p, pend);
 
223
    }
 
224
}
 
225
 
 
226
void
 
227
grub_envblk_iterate (grub_envblk_t envblk,
 
228
                     int hook (const char *name, const char *value))
 
229
{
 
230
  char *p, *pend;
 
231
 
 
232
  p = envblk->buf + sizeof (GRUB_ENVBLK_SIGNATURE) - 1;
 
233
  pend = envblk->buf + envblk->size;
 
234
 
 
235
  while (p < pend)
 
236
    {
 
237
      if (*p != '#')
 
238
        {
 
239
          char *name;
 
240
          char *value;
 
241
          char *name_start, *name_end, *value_start;
 
242
          char *q;
 
243
          int ret;
 
244
 
 
245
          name_start = p;
 
246
          while (p < pend && *p != '=')
 
247
            p++;
 
248
          if (p == pend)
 
249
            /* Broken.  */
 
250
            return;
 
251
          name_end = p;
 
252
 
 
253
          p++;
 
254
          value_start = p;
 
255
          while (p < pend)
 
256
            {
 
257
              if (*p == '\n')
 
258
                break;
 
259
              else if (*p == '\\')
 
260
                p += 2;
 
261
              else
 
262
                p++;
 
263
            }
 
264
 
 
265
          if (p >= pend)
 
266
            /* Broken.  */
 
267
            return;
 
268
 
 
269
          name = grub_malloc (p - name_start + 1);
 
270
          if (! name)
 
271
            /* out of memory.  */
 
272
            return;
 
273
 
 
274
          value = name + (value_start - name_start);
 
275
 
 
276
          grub_memcpy (name, name_start, name_end - name_start);
 
277
          name[name_end - name_start] = '\0';
 
278
 
 
279
          for (p = value_start, q = value; *p != '\n'; ++p)
 
280
            {
 
281
              if (*p == '\\')
 
282
                *q++ = *++p;
 
283
              else
 
284
                *q++ = *p;
 
285
            }
 
286
          *q = '\0';
 
287
 
 
288
          ret = hook (name, value);
 
289
          grub_free (name);
 
290
          if (ret)
 
291
            return;
 
292
        }
 
293
 
 
294
      p = find_next_line (p, pend);
 
295
    }
 
296
}