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

« back to all changes in this revision

Viewing changes to 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
 
              file = grub_file_open (args[*argn + 1]);
338
 
              update_val (file && (grub_file_size (file) != 0));
339
 
              if (file)
340
 
                grub_file_close (file);
341
 
              grub_errno = GRUB_ERR_NONE;
342
 
              (*argn) += 2;
343
 
              return ret;
344
 
            }
345
 
 
346
 
          /* String tests. */
347
 
          if (grub_strcmp (args[*argn], "-n") == 0)
348
 
            {
349
 
              update_val (args[*argn + 1][0]);
350
 
 
351
 
              (*argn) += 2;
352
 
              continue;
353
 
            }
354
 
          if (grub_strcmp (args[*argn], "-z") == 0)
355
 
            {
356
 
              update_val (! args[*argn + 1][0]);
357
 
              (*argn) += 2;
358
 
              continue;
359
 
            }
360
 
        }
361
 
 
362
 
      /* Special modifiers. */
363
 
 
364
 
      /* End of expression. return to parent. */
365
 
      if (grub_strcmp (args[*argn], ")") == 0)
366
 
        {
367
 
          (*argn)++;
368
 
          return ret;
369
 
        }
370
 
      /* Recursively invoke if parenthesis. */
371
 
      if (grub_strcmp (args[*argn], "(") == 0)
372
 
        {
373
 
          (*argn)++;
374
 
          update_val (test_parse (args, argn, argc));
375
 
          continue;
376
 
        }
377
 
 
378
 
      if (grub_strcmp (args[*argn], "!") == 0)
379
 
        {
380
 
          invert = ! invert;
381
 
          (*argn)++;
382
 
          continue;
383
 
        }
384
 
      if (grub_strcmp (args[*argn], "-a") == 0)
385
 
        {
386
 
          /* If current value is 0 second value is to be discarded. */
387
 
          discard = ! ret;
388
 
          (*argn)++;
389
 
          continue;
390
 
        }
391
 
      if (grub_strcmp (args[*argn], "-o") == 0)
392
 
        {
393
 
          /* If current value is 1 second value is to be discarded. */
394
 
          discard = ret;
395
 
          (*argn)++;
396
 
          continue;
397
 
        }
398
 
 
399
 
      /* No test found. Interpret if as just a string. */
400
 
      update_val (args[*argn][0]);
401
 
      (*argn)++;
402
 
    }
403
 
  return ret;
404
 
}
405
 
 
406
 
static grub_err_t
407
 
grub_cmd_test (grub_command_t cmd __attribute__ ((unused)),
408
 
               int argc, char **args)
409
 
{
410
 
  int argn = 0;
411
 
 
412
 
  if (argc >= 1 && grub_strcmp (args[argc - 1], "]") == 0)
413
 
    argc--;
414
 
 
415
 
  return test_parse (args, &argn, argc) ? GRUB_ERR_NONE
416
 
    : grub_error (GRUB_ERR_TEST_FAILURE, "false");
417
 
}
418
 
 
419
 
static grub_command_t cmd_1, cmd_2;
420
 
 
421
 
GRUB_MOD_INIT(test)
422
 
{
423
 
  cmd_1 = grub_register_command ("[", grub_cmd_test,
424
 
                                 N_("EXPRESSION ]"), N_("Evaluate an expression."));
425
 
  cmd_2 = grub_register_command ("test", grub_cmd_test,
426
 
                                 N_("EXPRESSION"), N_("Evaluate an expression."));
427
 
}
428
 
 
429
 
GRUB_MOD_FINI(test)
430
 
{
431
 
  grub_unregister_command (cmd_1);
432
 
  grub_unregister_command (cmd_2);
433
 
}