~hamo/ubuntu/precise/grub2/grub2.hi_res

« back to all changes in this revision

Viewing changes to grub-core/commands/wildcard.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson, Colin Watson, Evan Broder, Mario Limonciello
  • Date: 2010-11-24 13:59:55 UTC
  • mfrom: (1.17.6 upstream) (17.6.15 experimental)
  • Revision ID: james.westby@ubuntu.com-20101124135955-r6ii5sepayr7jt53
Tags: 1.99~20101124-1ubuntu1
[ Colin Watson ]
* Resynchronise with Debian experimental.  Remaining changes:
  - Adjust for default Ubuntu boot options ("quiet splash").
  - Default to hiding the menu; holding down Shift at boot will show it.
  - Set a monochromatic theme for Ubuntu.
  - Apply Ubuntu GRUB Legacy changes to legacy update-grub script: title,
    recovery mode, quiet option, tweak how memtest86+ is displayed, and
    use UUIDs where appropriate.
  - Fix backslash-escaping in merge_debconf_into_conf.
  - Remove "GNU/Linux" from default distributor string.
  - Add crashkernel= options if kdump and makedumpfile are available.
  - If other operating systems are installed, then automatically unhide
    the menu.  Otherwise, if GRUB_HIDDEN_TIMEOUT is 0, then use keystatus
    if available to check whether Shift is pressed.  If it is, show the
    menu, otherwise boot immediately.  If keystatus is not available, then
    fall back to a short delay interruptible with Escape.
  - Allow Shift to interrupt 'sleep --interruptible'.
  - Don't display introductory message about line editing unless we're
    actually offering a shell prompt.  Don't clear the screen just before
    booting if we never drew the menu in the first place.
  - Remove some verbose messages printed before reading the configuration
    file.
  - Suppress progress messages as the kernel and initrd load for
    non-recovery kernel menu entries.
  - Change prepare_grub_to_access_device to handle filesystems
    loop-mounted on file images.
  - Ignore devices loop-mounted from files in 10_linux.
  - Show the boot menu if the previous boot failed, that is if it failed
    to get to the end of one of the normal runlevels.
  - Don't generate /boot/grub/device.map during grub-install or
    grub-mkconfig by default.
  - Adjust upgrade version checks for Ubuntu.
  - Don't display "GRUB loading" unless Shift is held down.
  - Adjust versions of grub-doc and grub-legacy-doc conflicts to tolerate
    our backport of the grub-doc split.
  - Fix LVM/RAID probing in the absence of /boot/grub/device.map.
  - Look for .mo files in /usr/share/locale-langpack as well, in
    preference.
  - Make sure GRUB_TIMEOUT isn't quoted unnecessarily.
  - Probe all devices in 'grub-probe --target=drive' if
    /boot/grub/device.map is missing.
  - Build-depend on qemu-kvm rather than qemu-system for grub-pc tests.
  - Use qemu rather than qemu-system-i386.
  - Program vesafb on BIOS systems rather than efifb.
  - Add a grub-rescue-efi-amd64 package containing a rescue CD-ROM image
    for EFI-AMD64.
  - On Wubi, don't ask for an install device, but just update wubildr
    using the diverted grub-install.
  - When embedding the core image in a post-MBR gap, check for and avoid
    sectors matching any of a list of known signatures.
  - Disable video_bochs and video_cirrus on PC BIOS systems, as probing
    PCI space seems to break on some systems.
* Downgrade "ACPI shutdown failed" error to a debug message, since it can
  cause spurious test failures.

[ Evan Broder ]
* Enable lua from grub-extras.
* Incorporate the bitop library into lua.
* Add enum_pci function to grub module in lua.
* Switch back to gfxpayload=keep by default, unless the video hardware
  is known to not support it.

[ Mario Limonciello ]
* Built part_msdos and vfat into bootx64.efi (LP: #677758)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* wildcard.c - Wildcard character expansion for GRUB script.  */
 
2
/*
 
3
 *  GRUB  --  GRand Unified Bootloader
 
4
 *  Copyright (C) 2010  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/mm.h>
 
21
#include <grub/fs.h>
 
22
#include <grub/env.h>
 
23
#include <grub/file.h>
 
24
#include <grub/device.h>
 
25
#include <grub/script_sh.h>
 
26
 
 
27
#include <regex.h>
 
28
 
 
29
static inline int isregexop (char ch);
 
30
static char ** merge (char **lhs, char **rhs);
 
31
static char *make_dir (const char *prefix, const char *start, const char *end);
 
32
static int make_regex (const char *regex_start, const char *regex_end,
 
33
                       regex_t *regexp);
 
34
static void split_path (const char *path, const char **suffix_end, const char **regex_end);
 
35
static char ** match_devices (const regex_t *regexp, int noparts);
 
36
static char ** match_files (const char *prefix, const char *suffix_start,
 
37
                            const char *suffix_end, const regex_t *regexp);
 
38
 
 
39
static char* wildcard_escape (const char *s);
 
40
static char* wildcard_unescape (const char *s);
 
41
static grub_err_t wildcard_expand (const char *s, char ***strs);
 
42
 
 
43
struct grub_script_wildcard_translator grub_filename_translator = {
 
44
  .expand = wildcard_expand,
 
45
  .escape = wildcard_escape,
 
46
  .unescape = wildcard_unescape
 
47
};
 
48
 
 
49
static char **
 
50
merge (char **dest, char **ps)
 
51
{
 
52
  int i;
 
53
  int j;
 
54
  char **p;
 
55
 
 
56
  if (! dest)
 
57
    return ps;
 
58
 
 
59
  if (! ps)
 
60
    return dest;
 
61
 
 
62
  for (i = 0; dest[i]; i++)
 
63
    ;
 
64
  for (j = 0; ps[j]; j++)
 
65
    ;
 
66
 
 
67
  p = grub_realloc (dest, sizeof (char*) * (i + j + 1));
 
68
  if (! p)
 
69
    {
 
70
      grub_free (dest);
 
71
      grub_free (ps);
 
72
      return 0;
 
73
    }
 
74
 
 
75
  dest = p;
 
76
  for (j = 0; ps[j]; j++)
 
77
    dest[i++] = ps[j];
 
78
  dest[i] = 0;
 
79
 
 
80
  grub_free (ps);
 
81
  return dest;
 
82
}
 
83
 
 
84
static inline int
 
85
isregexop (char ch)
 
86
{
 
87
  return grub_strchr ("*.\\", ch) ? 1 : 0;
 
88
}
 
89
 
 
90
static char *
 
91
make_dir (const char *prefix, const char *start, const char *end)
 
92
{
 
93
  char ch;
 
94
  unsigned i;
 
95
  unsigned n;
 
96
  char *result;
 
97
 
 
98
  i = grub_strlen (prefix);
 
99
  n = i + end - start;
 
100
 
 
101
  result = grub_malloc (n + 1);
 
102
  if (! result)
 
103
    return 0;
 
104
 
 
105
  grub_strcpy (result, prefix);
 
106
  while (start < end && (ch = *start++))
 
107
    if (ch == '\\' && isregexop (*start))
 
108
      result[i++] = *start++;
 
109
    else
 
110
      result[i++] = ch;
 
111
 
 
112
  result[i] = '\0';
 
113
  return result;
 
114
}
 
115
 
 
116
static int
 
117
make_regex (const char *start, const char *end, regex_t *regexp)
 
118
{
 
119
  char ch;
 
120
  int i = 0;
 
121
  unsigned len = end - start;
 
122
  char *buffer = grub_malloc (len * 2 + 2 + 1); /* worst case size. */
 
123
 
 
124
  if (! buffer)
 
125
    return 1;
 
126
 
 
127
  buffer[i++] = '^';
 
128
  while (start < end)
 
129
    {
 
130
      /* XXX Only * expansion for now.  */
 
131
      switch ((ch = *start++))
 
132
        {
 
133
        case '\\':
 
134
          buffer[i++] = ch;
 
135
          if (*start != '\0')
 
136
            buffer[i++] = *start++;
 
137
          break;
 
138
 
 
139
        case '.':
 
140
        case '(':
 
141
        case ')':
 
142
          buffer[i++] = '\\';
 
143
          buffer[i++] = ch;
 
144
          break;
 
145
 
 
146
        case '*':
 
147
          buffer[i++] = '.';
 
148
          buffer[i++] = '*';
 
149
          break;
 
150
 
 
151
        default:
 
152
          buffer[i++] = ch;
 
153
        }
 
154
    }
 
155
  buffer[i++] = '$';
 
156
  buffer[i] = '\0';
 
157
  grub_dprintf ("expand", "Regexp is %s\n", buffer);
 
158
 
 
159
  if (regcomp (regexp, buffer, RE_SYNTAX_GNU_AWK))
 
160
    {
 
161
      grub_free (buffer);
 
162
      return 1;
 
163
    }
 
164
 
 
165
  grub_free (buffer);
 
166
  return 0;
 
167
}
 
168
 
 
169
/* Split `str' into two parts: (1) dirname that is regexop free (2)
 
170
   dirname that has a regexop.  */
 
171
static void
 
172
split_path (const char *str, const char **noregexop, const char **regexop)
 
173
{
 
174
  char ch = 0;
 
175
  int regex = 0;
 
176
 
 
177
  const char *end;
 
178
  const char *split;  /* points till the end of dirnaname that doesn't
 
179
                         need expansion.  */
 
180
 
 
181
  split = end = str;
 
182
  while ((ch = *end))
 
183
    {
 
184
      if (ch == '\\' && end[1])
 
185
        end++;
 
186
 
 
187
      else if (isregexop (ch))
 
188
        regex = 1;
 
189
 
 
190
      else if (ch == '/' && ! regex)
 
191
        split = end + 1;  /* forward to next regexop-free dirname */
 
192
 
 
193
      else if (ch == '/' && regex)
 
194
        break;  /* stop at the first dirname with a regexop */
 
195
 
 
196
      end++;
 
197
    }
 
198
 
 
199
  *regexop = end;
 
200
  if (! regex)
 
201
    *noregexop = end;
 
202
  else
 
203
    *noregexop = split;
 
204
}
 
205
 
 
206
static char **
 
207
match_devices (const regex_t *regexp, int noparts)
 
208
{
 
209
  int i;
 
210
  int ndev;
 
211
  char **devs;
 
212
 
 
213
  auto int match (const char *name);
 
214
  int match (const char *name)
 
215
  {
 
216
    char **t;
 
217
    char *buffer;
 
218
 
 
219
    /* skip partitions if asked to. */
 
220
    if (noparts && grub_strchr(name, ','))
 
221
      return 0;
 
222
 
 
223
    buffer = grub_xasprintf ("(%s)", name);
 
224
    if (! buffer)
 
225
      return 1;
 
226
 
 
227
    grub_dprintf ("expand", "matching: %s\n", buffer);
 
228
    if (regexec (regexp, buffer, 0, 0, 0))
 
229
      {
 
230
        grub_dprintf ("expand", "not matched\n");
 
231
        grub_free (buffer);
 
232
        return 0;
 
233
      }
 
234
 
 
235
    t = grub_realloc (devs, sizeof (char*) * (ndev + 2));
 
236
    if (! t)
 
237
      return 1;
 
238
 
 
239
    devs = t;
 
240
    devs[ndev++] = buffer;
 
241
    devs[ndev] = 0;
 
242
    return 0;
 
243
  }
 
244
 
 
245
  ndev = 0;
 
246
  devs = 0;
 
247
 
 
248
  if (grub_device_iterate (match))
 
249
    goto fail;
 
250
 
 
251
  return devs;
 
252
 
 
253
 fail:
 
254
 
 
255
  for (i = 0; devs && devs[i]; i++)
 
256
    grub_free (devs[i]);
 
257
 
 
258
  if (devs)
 
259
    grub_free (devs);
 
260
 
 
261
  return 0;
 
262
}
 
263
 
 
264
static char **
 
265
match_files (const char *prefix, const char *suffix, const char *end,
 
266
             const regex_t *regexp)
 
267
{
 
268
  int i;
 
269
  int error;
 
270
  char **files;
 
271
  unsigned nfile;
 
272
  char *dir;
 
273
  const char *path;
 
274
  char *device_name;
 
275
  grub_fs_t fs;
 
276
  grub_device_t dev;
 
277
 
 
278
  auto int match (const char *name, const struct grub_dirhook_info *info);
 
279
  int match (const char *name, const struct grub_dirhook_info *info)
 
280
  {
 
281
    char **t;
 
282
    char *buffer;
 
283
 
 
284
    /* skip . and .. names */
 
285
    if (grub_strcmp(".", name) == 0 || grub_strcmp("..", name) == 0)
 
286
      return 0;
 
287
 
 
288
    grub_dprintf ("expand", "matching: %s in %s\n", name, dir);
 
289
    if (regexec (regexp, name, 0, 0, 0))
 
290
      return 0;
 
291
 
 
292
    buffer = grub_xasprintf ("%s%s", dir, name);
 
293
    if (! buffer)
 
294
      return 1;
 
295
 
 
296
    t = grub_realloc (files, sizeof (char*) * (nfile + 2));
 
297
    if (! t)
 
298
      {
 
299
        grub_free (buffer);
 
300
        return 1;
 
301
      }
 
302
 
 
303
    files = t;
 
304
    files[nfile++] = buffer;
 
305
    files[nfile] = 0;
 
306
    return 0;
 
307
  }
 
308
 
 
309
  nfile = 0;
 
310
  files = 0;
 
311
  dev = 0;
 
312
  device_name = 0;
 
313
  grub_error_push ();
 
314
 
 
315
  dir = make_dir (prefix, suffix, end);
 
316
  if (! dir)
 
317
    goto fail;
 
318
 
 
319
  device_name = grub_file_get_device_name (dir);
 
320
  dev = grub_device_open (device_name);
 
321
  if (! dev)
 
322
    goto fail;
 
323
 
 
324
  fs = grub_fs_probe (dev);
 
325
  if (! fs)
 
326
    goto fail;
 
327
 
 
328
  path = grub_strchr (dir, ')');
 
329
  if (! path)
 
330
    goto fail;
 
331
  path++;
 
332
 
 
333
  if (fs->dir (dev, path, match))
 
334
    goto fail;
 
335
 
 
336
  grub_free (dir);
 
337
  grub_device_close (dev);
 
338
  grub_free (device_name);
 
339
  grub_error_pop ();
 
340
  return files;
 
341
 
 
342
 fail:
 
343
 
 
344
  if (dir)
 
345
    grub_free (dir);
 
346
 
 
347
  for (i = 0; files && files[i]; i++)
 
348
    grub_free (files[i]);
 
349
 
 
350
  if (files)
 
351
    grub_free (files);
 
352
 
 
353
  if (dev)
 
354
    grub_device_close (dev);
 
355
 
 
356
  if (device_name)
 
357
    grub_free (device_name);
 
358
 
 
359
  grub_error_pop ();
 
360
  return 0;
 
361
}
 
362
 
 
363
static char*
 
364
wildcard_escape (const char *s)
 
365
{
 
366
  int i;
 
367
  int len;
 
368
  char ch;
 
369
  char *p;
 
370
 
 
371
  len = grub_strlen (s);
 
372
  p = grub_malloc (len * 2 + 1);
 
373
  if (! p)
 
374
    return NULL;
 
375
 
 
376
  i = 0;
 
377
  while ((ch = *s++))
 
378
    {
 
379
      if (isregexop (ch))
 
380
        p[i++] = '\\';
 
381
      p[i++] = ch;
 
382
    }
 
383
  p[i] = '\0';
 
384
  return p;
 
385
}
 
386
 
 
387
static char*
 
388
wildcard_unescape (const char *s)
 
389
{
 
390
  int i;
 
391
  int len;
 
392
  char ch;
 
393
  char *p;
 
394
 
 
395
  len = grub_strlen (s);
 
396
  p = grub_malloc (len + 1);
 
397
  if (! p)
 
398
    return NULL;
 
399
 
 
400
  i = 0;
 
401
  while ((ch = *s++))
 
402
    {
 
403
      if (ch == '\\' && isregexop (*s))
 
404
        p[i++] = *s++;
 
405
      else
 
406
        p[i++] = ch;
 
407
    }
 
408
  p[i] = '\0';
 
409
  return p;
 
410
}
 
411
 
 
412
static grub_err_t
 
413
wildcard_expand (const char *s, char ***strs)
 
414
{
 
415
  const char *start;
 
416
  const char *regexop;
 
417
  const char *noregexop;
 
418
  char **paths = 0;
 
419
 
 
420
  unsigned i;
 
421
  regex_t regexp;
 
422
 
 
423
  start = s;
 
424
  while (*start)
 
425
    {
 
426
      split_path (start, &noregexop, &regexop);
 
427
      if (noregexop >= regexop) /* no more wildcards */
 
428
        break;
 
429
 
 
430
      if (make_regex (noregexop, regexop, &regexp))
 
431
        goto fail;
 
432
 
 
433
      if (paths == 0)
 
434
        {
 
435
          if (start == noregexop) /* device part has regexop */
 
436
            paths = match_devices (&regexp, *start != '(');
 
437
 
 
438
          else if (*start == '(') /* device part explicit wo regexop */
 
439
            paths = match_files ("", start, noregexop, &regexp);
 
440
 
 
441
          else if (*start == '/') /* no device part */
 
442
            {
 
443
              char **r;
 
444
              unsigned n;
 
445
              char *root;
 
446
              char *prefix;
 
447
 
 
448
              root = grub_env_get ("root");
 
449
              if (! root)
 
450
                goto fail;
 
451
 
 
452
              prefix = grub_xasprintf ("(%s)", root);
 
453
              if (! prefix)
 
454
                goto fail;
 
455
 
 
456
              paths = match_files (prefix, start, noregexop, &regexp);
 
457
              grub_free (prefix);
 
458
            }
 
459
        }
 
460
      else
 
461
        {
 
462
          char **r = 0;
 
463
 
 
464
          for (i = 0; paths[i]; i++)
 
465
            {
 
466
              char **p;
 
467
 
 
468
              p = match_files (paths[i], start, noregexop, &regexp);
 
469
              if (! p)
 
470
                continue;
 
471
 
 
472
              r = merge (r, p);
 
473
              if (! r)
 
474
                goto fail;
 
475
            }
 
476
          paths = r;
 
477
        }
 
478
 
 
479
      regfree (&regexp);
 
480
      if (! paths)
 
481
        goto done;
 
482
 
 
483
      start = regexop;
 
484
    }
 
485
 
 
486
 done:
 
487
 
 
488
  *strs = paths;
 
489
  return 0;
 
490
 
 
491
 fail:
 
492
 
 
493
  for (i = 0; paths && paths[i]; i++)
 
494
    grub_free (paths[i]);
 
495
  grub_free (paths);
 
496
  regfree (&regexp);
 
497
  return grub_errno;
 
498
}