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

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson, Colin Watson, Robert Millan, Updated translations
  • Date: 2010-11-22 12:24:56 UTC
  • mfrom: (1.26.4 upstream) (17.3.36 sid)
  • mto: (17.3.43 sid)
  • mto: This revision was merged to the branch mainline in revision 89.
  • Revision ID: james.westby@ubuntu.com-20101122122456-y82z3sfb7k4zfdcc
Tags: 1.99~20101122-1
[ Colin Watson ]
* New Bazaar snapshot.  Too many changes to list in full, but some of the
  more user-visible ones are as follows:
  - GRUB script:
    + Function parameters, "break", "continue", "shift", "setparams",
      "return", and "!".
    + "export" command supports multiple variable names.
    + Multi-line quoted strings support.
    + Wildcard expansion.
  - sendkey support.
  - USB hotunplugging and USB serial support.
  - Rename CD-ROM to cd on BIOS.
  - Add new --boot-directory option to grub-install, grub-reboot, and
    grub-set-default; the old --root-directory option is still accepted
    but was often confusing.
  - Basic btrfs detection/UUID support (but no file reading yet).
  - bash-completion for utilities.
  - If a device is listed in device.map, always assume that it is
    BIOS-visible rather than using extra layers such as LVM or RAID.
  - Add grub-mknetdir script (closes: #550658).
  - Remove deprecated "root" command.
  - Handle RAID devices containing virtio components.
  - GRUB Legacy configuration file support (via grub-menulst2cfg).
  - Keyboard layout support (via grub-mklayout and grub-kbdcomp).
  - Check generated grub.cfg for syntax errors before saving.
  - Pause execution for at most ten seconds if any errors are displayed,
    so that the user has a chance to see them.
  - Support submenus.
  - Write embedding zone using Reed-Solomon, so that it's robust against
    being partially overwritten (closes: #550702, #591416, #593347).
  - GRUB_DISABLE_LINUX_RECOVERY and GRUB_DISABLE_NETBSD_RECOVERY merged
    into a single GRUB_DISABLE_RECOVERY variable.
  - Fix loader memory allocation failure (closes: #551627).
  - Don't call savedefault on recovery entries (closes: #589325).
  - Support triple-indirect blocks on ext2 (closes: #543924).
  - Recognise DDF1 fake RAID (closes: #603354).

[ Robert Millan ]
* Use dpkg architecture wildcards.

[ Updated translations ]
* Slovenian (Vanja Cvelbar).  Closes: #604003
* Dzongkha (dawa pemo via Tenzin Dendup).  Closes: #604102

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* test.c -- The test command..  */
 
2
/*
 
3
 *  GRUB  --  GRand Unified Bootloader
 
4
 *  Copyright (C) 2005,2007,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/dl.h>
 
21
#include <grub/misc.h>
 
22
#include <grub/mm.h>
 
23
#include <grub/env.h>
 
24
#include <grub/fs.h>
 
25
#include <grub/device.h>
 
26
#include <grub/file.h>
 
27
#include <grub/command.h>
 
28
#include <grub/i18n.h>
 
29
 
 
30
/* A simple implementation for signed numbers. */
 
31
static int
 
32
grub_strtosl (char *arg, char **end, int base)
 
33
{
 
34
  if (arg[0] == '-')
 
35
    return -grub_strtoul (arg + 1, end, base);
 
36
  return grub_strtoul (arg, end, base);
 
37
}
 
38
 
 
39
/* Parse a test expression starting from *argn. */
 
40
static int
 
41
test_parse (char **args, int *argn, int argc)
 
42
{
 
43
  int ret = 0, discard = 0, invert = 0;
 
44
  int file_exists;
 
45
  struct grub_dirhook_info file_info;
 
46
 
 
47
  auto void update_val (int val);
 
48
  auto void get_fileinfo (char *pathname);
 
49
 
 
50
  /* Take care of discarding and inverting. */
 
51
  void update_val (int val)
 
52
  {
 
53
    if (! discard)
 
54
      ret = invert ? ! val : val;
 
55
    invert = discard = 0;
 
56
  }
 
57
 
 
58
  /* Check if file exists and fetch its information. */
 
59
  void get_fileinfo (char *path)
 
60
  {
 
61
    char *filename, *pathname;
 
62
    char *device_name;
 
63
    grub_fs_t fs;
 
64
    grub_device_t dev;
 
65
 
 
66
    /* A hook for iterating directories. */
 
67
    auto int find_file (const char *cur_filename,
 
68
                        const struct grub_dirhook_info *info);
 
69
    int find_file (const char *cur_filename,
 
70
                   const struct grub_dirhook_info *info)
 
71
    {
 
72
      if ((info->case_insensitive ? grub_strcasecmp (cur_filename, filename)
 
73
           : grub_strcmp (cur_filename, filename)) == 0)
 
74
        {
 
75
          file_info = *info;
 
76
          file_exists = 1;
 
77
          return 1;
 
78
        }
 
79
      return 0;
 
80
    }
 
81
 
 
82
    file_exists = 0;
 
83
    device_name = grub_file_get_device_name (path);
 
84
    dev = grub_device_open (device_name);
 
85
    if (! dev)
 
86
      {
 
87
        grub_free (device_name);
 
88
        return;
 
89
      }
 
90
 
 
91
    fs = grub_fs_probe (dev);
 
92
    if (! fs)
 
93
      {
 
94
        grub_free (device_name);
 
95
        grub_device_close (dev);
 
96
        return;
 
97
      }
 
98
 
 
99
    pathname = grub_strchr (path, ')');
 
100
    if (! pathname)
 
101
      pathname = path;
 
102
    else
 
103
      pathname++;
 
104
 
 
105
    /* Remove trailing '/'. */
 
106
    while (*pathname && pathname[grub_strlen (pathname) - 1] == '/')
 
107
      pathname[grub_strlen (pathname) - 1] = 0;
 
108
 
 
109
    /* Split into path and filename. */
 
110
    filename = grub_strrchr (pathname, '/');
 
111
    if (! filename)
 
112
      {
 
113
        path = grub_strdup ("/");
 
114
        filename = pathname;
 
115
      }
 
116
    else
 
117
      {
 
118
        filename++;
 
119
        path = grub_strdup (pathname);
 
120
        path[filename - pathname] = 0;
 
121
      }
 
122
 
 
123
    /* It's the whole device. */
 
124
    if (! *pathname)
 
125
      {
 
126
        file_exists = 1;
 
127
        grub_memset (&file_info, 0, sizeof (file_info));
 
128
        /* Root is always a directory. */
 
129
        file_info.dir = 1;
 
130
 
 
131
        /* Fetch writing time. */
 
132
        file_info.mtimeset = 0;
 
133
        if (fs->mtime)
 
134
          {
 
135
            if (! fs->mtime (dev, &file_info.mtime))
 
136
              file_info.mtimeset = 1;
 
137
            grub_errno = GRUB_ERR_NONE;
 
138
          }
 
139
      }
 
140
    else
 
141
      (fs->dir) (dev, path, find_file);
 
142
 
 
143
    grub_device_close (dev);
 
144
    grub_free (path);
 
145
    grub_free (device_name);
 
146
  }
 
147
 
 
148
  /* Here we have the real parsing. */
 
149
  while (*argn < argc)
 
150
    {
 
151
      /* First try 3 argument tests. */
 
152
      if (*argn + 2 < argc)
 
153
        {
 
154
          /* String tests. */
 
155
          if (grub_strcmp (args[*argn + 1], "=") == 0
 
156
              || grub_strcmp (args[*argn + 1], "==") == 0)
 
157
            {
 
158
              update_val (grub_strcmp (args[*argn], args[*argn + 2]) == 0);
 
159
              (*argn) += 3;
 
160
              continue;
 
161
            }
 
162
 
 
163
          if (grub_strcmp (args[*argn + 1], "!=") == 0)
 
164
            {
 
165
              update_val (grub_strcmp (args[*argn], args[*argn + 2]) != 0);
 
166
              (*argn) += 3;
 
167
              continue;
 
168
            }
 
169
 
 
170
          /* GRUB extension: lexicographical sorting. */
 
171
          if (grub_strcmp (args[*argn + 1], "<") == 0)
 
172
            {
 
173
              update_val (grub_strcmp (args[*argn], args[*argn + 2]) < 0);
 
174
              (*argn) += 3;
 
175
              continue;
 
176
            }
 
177
 
 
178
          if (grub_strcmp (args[*argn + 1], "<=") == 0)
 
179
            {
 
180
              update_val (grub_strcmp (args[*argn], args[*argn + 2]) <= 0);
 
181
              (*argn) += 3;
 
182
              continue;
 
183
            }
 
184
 
 
185
          if (grub_strcmp (args[*argn + 1], ">") == 0)
 
186
            {
 
187
              update_val (grub_strcmp (args[*argn], args[*argn + 2]) > 0);
 
188
              (*argn) += 3;
 
189
              continue;
 
190
            }
 
191
 
 
192
          if (grub_strcmp (args[*argn + 1], ">=") == 0)
 
193
            {
 
194
              update_val (grub_strcmp (args[*argn], args[*argn + 2]) >= 0);
 
195
              (*argn) += 3;
 
196
              continue;
 
197
            }
 
198
 
 
199
          /* Number tests. */
 
200
          if (grub_strcmp (args[*argn + 1], "-eq") == 0)
 
201
            {
 
202
              update_val (grub_strtosl (args[*argn], 0, 0)
 
203
                          == grub_strtosl (args[*argn + 2], 0, 0));
 
204
              (*argn) += 3;
 
205
              continue;
 
206
            }
 
207
 
 
208
          if (grub_strcmp (args[*argn + 1], "-ge") == 0)
 
209
            {
 
210
              update_val (grub_strtosl (args[*argn], 0, 0)
 
211
                          >= grub_strtosl (args[*argn + 2], 0, 0));
 
212
              (*argn) += 3;
 
213
              continue;
 
214
            }
 
215
 
 
216
          if (grub_strcmp (args[*argn + 1], "-gt") == 0)
 
217
            {
 
218
              update_val (grub_strtosl (args[*argn], 0, 0)
 
219
                          > grub_strtosl (args[*argn + 2], 0, 0));
 
220
              (*argn) += 3;
 
221
              continue;
 
222
            }
 
223
 
 
224
          if (grub_strcmp (args[*argn + 1], "-le") == 0)
 
225
            {
 
226
              update_val (grub_strtosl (args[*argn], 0, 0)
 
227
                      <= grub_strtosl (args[*argn + 2], 0, 0));
 
228
              (*argn) += 3;
 
229
              continue;
 
230
            }
 
231
 
 
232
          if (grub_strcmp (args[*argn + 1], "-lt") == 0)
 
233
            {
 
234
              update_val (grub_strtosl (args[*argn], 0, 0)
 
235
                          < grub_strtosl (args[*argn + 2], 0, 0));
 
236
              (*argn) += 3;
 
237
              continue;
 
238
            }
 
239
 
 
240
          if (grub_strcmp (args[*argn + 1], "-ne") == 0)
 
241
            {
 
242
              update_val (grub_strtosl (args[*argn], 0, 0)
 
243
                          != grub_strtosl (args[*argn + 2], 0, 0));
 
244
              (*argn) += 3;
 
245
              continue;
 
246
            }
 
247
 
 
248
          /* GRUB extension: compare numbers skipping prefixes.
 
249
             Useful for comparing versions. E.g. vmlinuz-2 -plt vmlinuz-11. */
 
250
          if (grub_strcmp (args[*argn + 1], "-pgt") == 0
 
251
              || grub_strcmp (args[*argn + 1], "-plt") == 0)
 
252
            {
 
253
              int i;
 
254
              /* Skip common prefix. */
 
255
              for (i = 0; args[*argn][i] == args[*argn + 2][i]
 
256
                     && args[*argn][i]; i++);
 
257
 
 
258
              /* Go the digits back. */
 
259
              i--;
 
260
              while (grub_isdigit (args[*argn][i]) && i > 0)
 
261
                i--;
 
262
              i++;
 
263
 
 
264
              if (grub_strcmp (args[*argn + 1], "-pgt") == 0)
 
265
                update_val (grub_strtoul (args[*argn] + i, 0, 0)
 
266
                            > grub_strtoul (args[*argn + 2] + i, 0, 0));
 
267
              else
 
268
                update_val (grub_strtoul (args[*argn] + i, 0, 0)
 
269
                            < grub_strtoul (args[*argn + 2] + i, 0, 0));
 
270
              (*argn) += 3;
 
271
              continue;
 
272
            }
 
273
 
 
274
          /* -nt and -ot tests. GRUB extension: when doing -?t<bias> bias
 
275
             will be added to the first mtime. */
 
276
          if (grub_memcmp (args[*argn + 1], "-nt", 3) == 0
 
277
              || grub_memcmp (args[*argn + 1], "-ot", 3) == 0)
 
278
            {
 
279
              struct grub_dirhook_info file1;
 
280
              int file1exists;
 
281
              int bias = 0;
 
282
 
 
283
              /* Fetch fileinfo. */
 
284
              get_fileinfo (args[*argn]);
 
285
              file1 = file_info;
 
286
              file1exists = file_exists;
 
287
              get_fileinfo (args[*argn + 2]);
 
288
 
 
289
              if (args[*argn + 1][3])
 
290
                bias = grub_strtosl (args[*argn + 1] + 3, 0, 0);
 
291
 
 
292
              if (grub_memcmp (args[*argn + 1], "-nt", 3) == 0)
 
293
                update_val ((file1exists && ! file_exists)
 
294
                            || (file1.mtimeset && file_info.mtimeset
 
295
                                && file1.mtime + bias > file_info.mtime));
 
296
              else
 
297
                update_val ((! file1exists && file_exists)
 
298
                            || (file1.mtimeset && file_info.mtimeset
 
299
                                && file1.mtime + bias < file_info.mtime));
 
300
              (*argn) += 3;
 
301
              continue;
 
302
            }
 
303
        }
 
304
 
 
305
      /* Two-argument tests. */
 
306
      if (*argn + 1 < argc)
 
307
        {
 
308
          /* File tests. */
 
309
          if (grub_strcmp (args[*argn], "-d") == 0)
 
310
            {
 
311
              get_fileinfo (args[*argn + 1]);
 
312
              update_val (file_exists && file_info.dir);
 
313
              (*argn) += 2;
 
314
              return ret;
 
315
            }
 
316
 
 
317
          if (grub_strcmp (args[*argn], "-e") == 0)
 
318
            {
 
319
              get_fileinfo (args[*argn + 1]);
 
320
              update_val (file_exists);
 
321
              (*argn) += 2;
 
322
              return ret;
 
323
            }
 
324
 
 
325
          if (grub_strcmp (args[*argn], "-f") == 0)
 
326
            {
 
327
              get_fileinfo (args[*argn + 1]);
 
328
              /* FIXME: check for other types. */
 
329
              update_val (file_exists && ! file_info.dir);
 
330
              (*argn) += 2;
 
331
              return ret;
 
332
            }
 
333
 
 
334
          if (grub_strcmp (args[*argn], "-s") == 0)
 
335
            {
 
336
              grub_file_t file;
 
337
              grub_file_filter_disable_compression ();
 
338
              file = grub_file_open (args[*argn + 1]);
 
339
              update_val (file && (grub_file_size (file) != 0));
 
340
              if (file)
 
341
                grub_file_close (file);
 
342
              grub_errno = GRUB_ERR_NONE;
 
343
              (*argn) += 2;
 
344
              return ret;
 
345
            }
 
346
 
 
347
          /* String tests. */
 
348
          if (grub_strcmp (args[*argn], "-n") == 0)
 
349
            {
 
350
              update_val (args[*argn + 1][0]);
 
351
 
 
352
              (*argn) += 2;
 
353
              continue;
 
354
            }
 
355
          if (grub_strcmp (args[*argn], "-z") == 0)
 
356
            {
 
357
              update_val (! args[*argn + 1][0]);
 
358
              (*argn) += 2;
 
359
              continue;
 
360
            }
 
361
        }
 
362
 
 
363
      /* Special modifiers. */
 
364
 
 
365
      /* End of expression. return to parent. */
 
366
      if (grub_strcmp (args[*argn], ")") == 0)
 
367
        {
 
368
          (*argn)++;
 
369
          return ret;
 
370
        }
 
371
      /* Recursively invoke if parenthesis. */
 
372
      if (grub_strcmp (args[*argn], "(") == 0)
 
373
        {
 
374
          (*argn)++;
 
375
          update_val (test_parse (args, argn, argc));
 
376
          continue;
 
377
        }
 
378
 
 
379
      if (grub_strcmp (args[*argn], "!") == 0)
 
380
        {
 
381
          invert = ! invert;
 
382
          (*argn)++;
 
383
          continue;
 
384
        }
 
385
      if (grub_strcmp (args[*argn], "-a") == 0)
 
386
        {
 
387
          /* If current value is 0 second value is to be discarded. */
 
388
          discard = ! ret;
 
389
          (*argn)++;
 
390
          continue;
 
391
        }
 
392
      if (grub_strcmp (args[*argn], "-o") == 0)
 
393
        {
 
394
          /* If current value is 1 second value is to be discarded. */
 
395
          discard = ret;
 
396
          (*argn)++;
 
397
          continue;
 
398
        }
 
399
 
 
400
      /* No test found. Interpret if as just a string. */
 
401
      update_val (args[*argn][0]);
 
402
      (*argn)++;
 
403
    }
 
404
  return ret;
 
405
}
 
406
 
 
407
static grub_err_t
 
408
grub_cmd_test (grub_command_t cmd __attribute__ ((unused)),
 
409
               int argc, char **args)
 
410
{
 
411
  int argn = 0;
 
412
 
 
413
  if (argc >= 1 && grub_strcmp (args[argc - 1], "]") == 0)
 
414
    argc--;
 
415
 
 
416
  return test_parse (args, &argn, argc) ? GRUB_ERR_NONE
 
417
    : grub_error (GRUB_ERR_TEST_FAILURE, "false");
 
418
}
 
419
 
 
420
static grub_command_t cmd_1, cmd_2;
 
421
 
 
422
GRUB_MOD_INIT(test)
 
423
{
 
424
  cmd_1 = grub_register_command ("[", grub_cmd_test,
 
425
                                 N_("EXPRESSION ]"), N_("Evaluate an expression."));
 
426
  cmd_1->flags |= GRUB_COMMAND_FLAG_EXTRACTOR;
 
427
  cmd_2 = grub_register_command ("test", grub_cmd_test,
 
428
                                 N_("EXPRESSION"), N_("Evaluate an expression."));
 
429
  cmd_2->flags |= GRUB_COMMAND_FLAG_EXTRACTOR;
 
430
}
 
431
 
 
432
GRUB_MOD_FINI(test)
 
433
{
 
434
  grub_unregister_command (cmd_1);
 
435
  grub_unregister_command (cmd_2);
 
436
}