]> git.proxmox.com Git - grub2.git/blame - util/grub-fstest.c
fs/ntfs: Fix various OOB reads and writes (CVE-2023-4692, CVE-2023-4693)
[grub2.git] / util / grub-fstest.c
CommitLineData
99fadbaa 1/* grub-fstest.c - debug tool for filesystem driver */
2/*
3 * GRUB -- GRand Unified Bootloader
2f1a3acf 4 * Copyright (C) 2008,2009,2010 Free Software Foundation, Inc.
99fadbaa 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>
8c411768 22#include <grub/emu/misc.h>
99fadbaa 23#include <grub/util/misc.h>
24#include <grub/misc.h>
25#include <grub/device.h>
26#include <grub/disk.h>
27#include <grub/file.h>
28#include <grub/fs.h>
29#include <grub/env.h>
30#include <grub/term.h>
31#include <grub/mm.h>
a85cd5a0 32#include <grub/lib/hexdump.h>
c55f5018 33#include <grub/crypto.h>
b1b797cb 34#include <grub/command.h>
8a4c07fd 35#include <grub/i18n.h>
2cdc8995 36#include <grub/zfs/zfs.h>
df1e64c9 37#include <grub/emu/hostfile.h>
99fadbaa 38
99fadbaa 39#include <stdio.h>
df1e64c9 40#include <errno.h>
99fadbaa 41#include <string.h>
dab797f4 42
8a4c07fd 43#include "progname.h"
ca3e2088
VS
44#pragma GCC diagnostic ignored "-Wmissing-prototypes"
45#pragma GCC diagnostic ignored "-Wmissing-declarations"
3286a4b4 46#include "argp.h"
ca3e2088
VS
47#pragma GCC diagnostic error "-Wmissing-prototypes"
48#pragma GCC diagnostic error "-Wmissing-declarations"
8a4c07fd 49
36747a62 50static grub_err_t
1b024b4e 51execute_command (const char *name, int n, char **args)
99fadbaa 52{
b1b797cb 53 grub_command_t cmd;
99fadbaa 54
b1b797cb 55 cmd = grub_command_find (name);
56 if (! cmd)
d61386e2 57 grub_util_error (_("can't find command `%s'"), name);
99fadbaa 58
b1b797cb 59 return (cmd->func) (cmd, n, args);
99fadbaa 60}
61
3ca2b466
CW
62enum {
63 CMD_LS = 1,
64 CMD_CP,
65 CMD_CAT,
66 CMD_CMP,
67 CMD_HEX,
68 CMD_CRC,
77ba5392 69 CMD_BLOCKLIST,
11e50e92 70 CMD_TESTLOAD,
3be82e10
VS
71 CMD_ZFSINFO,
72 CMD_XNU_UUID
3ca2b466 73};
99fadbaa 74#define BUF_SIZE 32256
75
71ee178a 76static grub_disk_addr_t skip, leng;
7dc3c686 77static int uncompress = 0;
99fadbaa 78
79static void
6c69e691 80read_file (char *pathname, int (*hook) (grub_off_t ofs, char *buf, int len, void *hook_arg), void *hook_arg)
99fadbaa 81{
82 static char buf[BUF_SIZE];
83 grub_file_t file;
99fadbaa 84
5ed20adc 85 if ((pathname[0] == '-') && (pathname[1] == 0))
86 {
87 grub_device_t dev;
88
89 dev = grub_device_open (0);
90 if ((! dev) || (! dev->disk))
1b024b4e 91 grub_util_error ("%s", grub_errmsg);
5ed20adc 92
18e76955 93 grub_util_info ("total sectors : %" GRUB_HOST_PRIuLONG_LONG,
5ed20adc 94 (unsigned long long) dev->disk->total_sectors);
95
96 if (! leng)
97 leng = (dev->disk->total_sectors << GRUB_DISK_SECTOR_BITS) - skip;
98
99 while (leng)
100 {
101 grub_size_t len;
102
103 len = (leng > BUF_SIZE) ? BUF_SIZE : leng;
104
105 if (grub_disk_read (dev->disk, 0, skip, len, buf))
f4dab3d1
VS
106 {
107 char *msg = grub_xasprintf (_("disk read fails at offset %lld, length %lld"),
108 (long long) skip, (long long) len);
109 grub_util_error ("%s", msg);
110 }
5ed20adc 111
6c69e691 112 if (hook (skip, buf, len, hook_arg))
5ed20adc 113 break;
114
115 skip += len;
116 leng -= len;
117 }
118
119 grub_device_close (dev);
120 return;
121 }
122
ca0a4f68
VS
123 file = grub_file_open (pathname, ((uncompress == 0)
124 ? GRUB_FILE_TYPE_NO_DECOMPRESS : GRUB_FILE_TYPE_NONE)
125 | GRUB_FILE_TYPE_FSTEST);
99fadbaa 126 if (!file)
127 {
b525fd83 128 grub_util_error (_("cannot open `%s': %s"), pathname,
af869a4a 129 grub_errmsg);
99fadbaa 130 return;
131 }
132
18e76955
VS
133 grub_util_info ("file size : %" GRUB_HOST_PRIuLONG_LONG,
134 (unsigned long long) file->size);
5ed20adc 135
99fadbaa 136 if (skip > file->size)
137 {
f4dab3d1
VS
138 char *msg = grub_xasprintf (_("invalid skip value %lld"),
139 (unsigned long long) skip);
140 grub_util_error ("%s", msg);
99fadbaa 141 return;
142 }
143
1b024b4e
VS
144 {
145 grub_off_t ofs, len;
146 ofs = skip;
147 len = file->size - skip;
148 if ((leng) && (leng < len))
149 len = leng;
99fadbaa 150
1b024b4e 151 file->offset = skip;
99fadbaa 152
1b024b4e
VS
153 while (len)
154 {
155 grub_ssize_t sz;
99fadbaa 156
1b024b4e
VS
157 sz = grub_file_read (file, buf, (len > BUF_SIZE) ? BUF_SIZE : len);
158 if (sz < 0)
159 {
f4dab3d1
VS
160 char *msg = grub_xasprintf (_("read error at offset %llu: %s"),
161 (unsigned long long) ofs, grub_errmsg);
162 grub_util_error ("%s", msg);
1b024b4e
VS
163 break;
164 }
99fadbaa 165
6c69e691 166 if ((sz == 0) || (hook (ofs, buf, sz, hook_arg)))
1b024b4e 167 break;
99fadbaa 168
1b024b4e
VS
169 ofs += sz;
170 len -= sz;
171 }
172 }
99fadbaa 173
174 grub_file_close (file);
175}
176
6c69e691 177struct cp_hook_ctx
99fadbaa 178{
179 FILE *ff;
6c69e691
VS
180 const char *dest;
181};
99fadbaa 182
6c69e691
VS
183static int
184cp_hook (grub_off_t ofs, char *buf, int len, void *_ctx)
185{
186 struct cp_hook_ctx *ctx = _ctx;
187 (void) ofs;
99fadbaa 188
6c69e691
VS
189 if ((int) fwrite (buf, 1, len, ctx->ff) != len)
190 {
191 grub_util_error (_("cannot write to `%s': %s"),
192 ctx->dest, strerror (errno));
193 return 1;
194 }
99fadbaa 195
6c69e691
VS
196 return 0;
197}
99fadbaa 198
6c69e691
VS
199static void
200cmd_cp (char *src, const char *dest)
201{
202 struct cp_hook_ctx ctx =
203 {
204 .dest = dest
205 };
206
bb338aaf 207 ctx.ff = grub_util_fopen (dest, "wb");
6c69e691 208 if (ctx.ff == NULL)
99fadbaa 209 {
b525fd83 210 grub_util_error (_("cannot open OS file `%s': %s"), dest,
42b2a706 211 strerror (errno));
99fadbaa 212 return;
213 }
6c69e691
VS
214 read_file (src, cp_hook, &ctx);
215 fclose (ctx.ff);
216}
217
218static int
219cat_hook (grub_off_t ofs, char *buf, int len, void *_arg __attribute__ ((unused)))
220{
221 (void) ofs;
222
223 if ((int) fwrite (buf, 1, len, stdout) != len)
224 {
225 grub_util_error (_("cannot write to the stdout: %s"),
226 strerror (errno));
227 return 1;
228 }
229
230 return 0;
99fadbaa 231}
232
3ca2b466
CW
233static void
234cmd_cat (char *src)
235{
6c69e691
VS
236 read_file (src, cat_hook, 0);
237}
3ca2b466 238
6c69e691
VS
239static int
240cmp_hook (grub_off_t ofs, char *buf, int len, void *ff_in)
241{
242 FILE *ff = ff_in;
243 static char buf_1[BUF_SIZE];
244 if ((int) fread (buf_1, 1, len, ff) != len)
245 {
f4dab3d1
VS
246 char *msg = grub_xasprintf (_("read error at offset %llu: %s"),
247 (unsigned long long) ofs, grub_errmsg);
248 grub_util_error ("%s", msg);
6c69e691
VS
249 return 1;
250 }
3ca2b466 251
6c69e691
VS
252 if (grub_memcmp (buf, buf_1, len) != 0)
253 {
254 int i;
3ca2b466 255
6c69e691
VS
256 for (i = 0; i < len; i++, ofs++)
257 if (buf_1[i] != buf[i])
258 {
f4dab3d1
VS
259 char *msg = grub_xasprintf (_("compare fail at offset %llu"),
260 (unsigned long long) ofs);
261 grub_util_error ("%s", msg);
6c69e691
VS
262 return 1;
263 }
264 }
265 return 0;
3ca2b466
CW
266}
267
6c69e691 268
99fadbaa 269static void
270cmd_cmp (char *src, char *dest)
271{
272 FILE *ff;
99fadbaa 273
df1e64c9 274 if (grub_util_is_directory (dest))
dab797f4 275 {
df1e64c9
VS
276 grub_util_fd_dir_t dir = grub_util_fd_opendir (dest);
277 grub_util_fd_dirent_t entry;
dab797f4
VS
278 if (dir == NULL)
279 {
280 grub_util_error (_("OS file %s open error: %s"), dest,
df1e64c9 281 grub_util_fd_strerror ());
dab797f4
VS
282 return;
283 }
df1e64c9 284 while ((entry = grub_util_fd_readdir (dir)))
dab797f4
VS
285 {
286 char *srcnew, *destnew;
287 char *ptr;
288 if (strcmp (entry->d_name, ".") == 0
289 || strcmp (entry->d_name, "..") == 0)
290 continue;
291 srcnew = xmalloc (strlen (src) + sizeof ("/")
292 + strlen (entry->d_name));
293 destnew = xmalloc (strlen (dest) + sizeof ("/")
294 + strlen (entry->d_name));
ba44ca6d 295 ptr = grub_stpcpy (srcnew, src);
dab797f4
VS
296 *ptr++ = '/';
297 strcpy (ptr, entry->d_name);
ba44ca6d 298 ptr = grub_stpcpy (destnew, dest);
dab797f4
VS
299 *ptr++ = '/';
300 strcpy (ptr, entry->d_name);
301
df1e64c9 302 if (grub_util_is_special_file (destnew))
dab797f4
VS
303 continue;
304
305 cmd_cmp (srcnew, destnew);
306 }
df1e64c9 307 grub_util_fd_closedir (dir);
dab797f4
VS
308 return;
309 }
310
bb338aaf 311 ff = grub_util_fopen (dest, "rb");
99fadbaa 312 if (ff == NULL)
313 {
42b2a706
VS
314 grub_util_error (_("OS file %s open error: %s"), dest,
315 strerror (errno));
99fadbaa 316 return;
317 }
318
828a2768 319 if ((skip) && (fseeko (ff, skip, SEEK_SET)))
9c4b5c13 320 grub_util_error (_("cannot seek `%s': %s"), dest,
0ae70393 321 strerror (errno));
99fadbaa 322
6c69e691 323 read_file (src, cmp_hook, ff);
8a3bc88e
VS
324
325 {
326 grub_uint64_t pre;
327 pre = ftell (ff);
328 fseek (ff, 0, SEEK_END);
329 if (pre != ftell (ff))
1b024b4e 330 grub_util_error ("%s", _("unexpected end of file"));
8a3bc88e 331 }
99fadbaa 332 fclose (ff);
333}
334
6c69e691
VS
335static int
336hex_hook (grub_off_t ofs, char *buf, int len, void *arg __attribute__ ((unused)))
337{
338 hexdump (ofs, buf, len);
339 return 0;
340}
341
99fadbaa 342static void
343cmd_hex (char *pathname)
344{
6c69e691
VS
345 read_file (pathname, hex_hook, 0);
346}
99fadbaa 347
6c69e691
VS
348static int
349crc_hook (grub_off_t ofs, char *buf, int len, void *crc_ctx)
350{
351 (void) ofs;
352
353 GRUB_MD_CRC32->write(crc_ctx, buf, len);
354 return 0;
99fadbaa 355}
356
357static void
5ed20adc 358cmd_crc (char *pathname)
99fadbaa 359{
621e167f 360 grub_uint8_t *crc32_context = xmalloc (GRUB_MD_CRC32->contextsize);
c55f5018 361 GRUB_MD_CRC32->init(crc32_context);
5ed20adc 362
6c69e691 363 read_file (pathname, crc_hook, crc32_context);
c55f5018
SJ
364 GRUB_MD_CRC32->final(crc32_context);
365 printf ("%08x\n",
8dcbe03b 366 grub_be_to_cpu32 (grub_get_unaligned32 (GRUB_MD_CRC32->read (crc32_context))));
621e167f 367 free (crc32_context);
5ed20adc 368}
99fadbaa 369
1b024b4e 370static const char *root = NULL;
3286a4b4
VS
371static int args_count = 0;
372static int nparm = 0;
373static int num_disks = 1;
374static char **images = NULL;
375static int cmd = 0;
376static char *debug_str = NULL;
377static char **args = NULL;
41692608 378static int mount_crypt = 0;
3286a4b4 379
5ed20adc 380static void
1b024b4e 381fstest (int n)
5ed20adc 382{
8b442f3f
VS
383 char *host_file;
384 char *loop_name;
5ed20adc 385 int i;
99fadbaa 386
5ed20adc 387 for (i = 0; i < num_disks; i++)
99fadbaa 388 {
94564f81 389 char *argv[2];
61eb45ee 390 loop_name = grub_xasprintf ("loop%d", i);
af75a9f1 391 if (!loop_name)
1b024b4e 392 grub_util_error ("%s", grub_errmsg);
99fadbaa 393
af75a9f1
RM
394 host_file = grub_xasprintf ("(host)%s", images[i]);
395 if (!host_file)
1b024b4e 396 grub_util_error ("%s", grub_errmsg);
8b442f3f 397
94564f81
VS
398 argv[0] = loop_name;
399 argv[1] = host_file;
99fadbaa 400
94564f81 401 if (execute_command ("loopback", 2, argv))
9c4b5c13 402 grub_util_error (_("`loopback' command fails: %s"), grub_errmsg);
af75a9f1
RM
403
404 grub_free (loop_name);
405 grub_free (host_file);
5ed20adc 406 }
99fadbaa 407
41692608 408 {
41692608 409 if (mount_crypt)
1a1f408f 410 {
102fae4a 411 char *argv[2] = { xstrdup ("-a"), NULL};
20a40940 412 if (execute_command ("cryptomount", 1, argv))
1b024b4e
VS
413 grub_util_error (_("`cryptomount' command fails: %s"),
414 grub_errmsg);
102fae4a 415 free (argv[0]);
1a1f408f 416 }
41692608
VS
417 }
418
076e7c0f 419 grub_ldm_fini ();
f45d6cfc 420 grub_lvm_fini ();
1e8d555b
VS
421 grub_mdraid09_fini ();
422 grub_mdraid1x_fini ();
076e7c0f
VS
423 grub_diskfilter_fini ();
424 grub_diskfilter_init ();
1e8d555b
VS
425 grub_mdraid09_init ();
426 grub_mdraid1x_init ();
f45d6cfc 427 grub_lvm_init ();
076e7c0f 428 grub_ldm_init ();
f45d6cfc 429
99fadbaa 430 switch (cmd)
431 {
432 case CMD_LS:
b1b797cb 433 execute_command ("ls", n, args);
99fadbaa 434 break;
fdfde32a 435 case CMD_ZFSINFO:
bed78ef4 436 execute_command ("zfsinfo", n, args);
fdfde32a 437 break;
99fadbaa 438 case CMD_CP:
439 cmd_cp (args[0], args[1]);
440 break;
3ca2b466
CW
441 case CMD_CAT:
442 cmd_cat (args[0]);
443 break;
99fadbaa 444 case CMD_CMP:
445 cmd_cmp (args[0], args[1]);
446 break;
447 case CMD_HEX:
448 cmd_hex (args[0]);
449 break;
5ed20adc 450 case CMD_CRC:
451 cmd_crc (args[0]);
452 break;
99fadbaa 453 case CMD_BLOCKLIST:
b1b797cb 454 execute_command ("blocklist", n, args);
99fadbaa 455 grub_printf ("\n");
1c557d30 456 break;
77ba5392
VS
457 case CMD_TESTLOAD:
458 execute_command ("testload", n, args);
459 grub_printf ("\n");
1c557d30 460 break;
3be82e10
VS
461 case CMD_XNU_UUID:
462 {
463 grub_device_t dev;
464 grub_fs_t fs;
465 char *uuid = 0;
102fae4a 466 char *argv[3] = { xstrdup ("-l"), NULL, NULL};
3be82e10
VS
467 dev = grub_device_open (n ? args[0] : 0);
468 if (!dev)
1b024b4e 469 grub_util_error ("%s", grub_errmsg);
3be82e10
VS
470 fs = grub_fs_probe (dev);
471 if (!fs)
1b024b4e 472 grub_util_error ("%s", grub_errmsg);
ad4bfeec 473 if (!fs->fs_uuid)
1b024b4e 474 grub_util_error ("%s", _("couldn't retrieve UUID"));
ad4bfeec 475 if (fs->fs_uuid (dev, &uuid))
1b024b4e 476 grub_util_error ("%s", grub_errmsg);
3be82e10 477 if (!uuid)
1b024b4e 478 grub_util_error ("%s", _("couldn't retrieve UUID"));
3be82e10 479 argv[1] = uuid;
8a5a3a5b 480 execute_command ("xnu_uuid", 2, argv);
102fae4a 481 grub_free (argv[0]);
8a5a3a5b
VS
482 grub_free (uuid);
483 grub_device_close (dev);
3be82e10 484 }
99fadbaa 485 }
94564f81 486
5ed20adc 487 for (i = 0; i < num_disks; i++)
488 {
94564f81
VS
489 char *argv[2];
490
61eb45ee 491 loop_name = grub_xasprintf ("loop%d", i);
8b442f3f 492 if (!loop_name)
1b024b4e 493 grub_util_error ("%s", grub_errmsg);
af75a9f1 494
102fae4a 495 argv[0] = xstrdup ("-d");
af75a9f1
RM
496 argv[1] = loop_name;
497
b1b797cb 498 execute_command ("loopback", 2, argv);
8b442f3f 499
af75a9f1 500 grub_free (loop_name);
102fae4a 501 grub_free (argv[0]);
af75a9f1 502 }
99fadbaa 503}
504
3286a4b4
VS
505static struct argp_option options[] = {
506 {0, 0, 0 , OPTION_DOC, N_("Commands:"), 1},
507 {N_("ls PATH"), 0, 0 , OPTION_DOC, N_("List files in PATH."), 1},
508 {N_("cp FILE LOCAL"), 0, 0, OPTION_DOC, N_("Copy FILE to local file LOCAL."), 1},
3ca2b466 509 {N_("cat FILE"), 0, 0 , OPTION_DOC, N_("Copy FILE to standard output."), 1},
3286a4b4 510 {N_("cmp FILE LOCAL"), 0, 0, OPTION_DOC, N_("Compare FILE with local file LOCAL."), 1},
9c4b5c13 511 {N_("hex FILE"), 0, 0 , OPTION_DOC, N_("Show contents of FILE in hex."), 1},
3286a4b4
VS
512 {N_("crc FILE"), 0, 0 , OPTION_DOC, N_("Get crc32 checksum of FILE."), 1},
513 {N_("blocklist FILE"), 0, 0, OPTION_DOC, N_("Display blocklist of FILE."), 1},
b5c1f9bf 514 {N_("xnu_uuid DEVICE"), 0, 0, OPTION_DOC, N_("Compute XNU UUID of the device."), 1},
3286a4b4
VS
515
516 {"root", 'r', N_("DEVICE_NAME"), 0, N_("Set root device."), 2},
fae01f6c
VS
517 {"skip", 's', N_("NUM"), 0, N_("Skip N bytes from output file."), 2},
518 {"length", 'n', N_("NUM"), 0, N_("Handle N bytes in output file."), 2},
519 {"diskcount", 'c', N_("NUM"), 0, N_("Specify the number of input files."), 2},
520 {"debug", 'd', N_("STRING"), 0, N_("Set debug environment variable."), 2},
97ebda9b 521 {"crypto", 'C', NULL, 0, N_("Mount crypto devices."), 2},
9c4b5c13
VS
522 {"zfs-key", 'K',
523 /* TRANSLATORS: "prompt" is a keyword. */
524 N_("FILE|prompt"), 0, N_("Load zfs crypto key."), 2},
97ebda9b
VS
525 {"verbose", 'v', NULL, 0, N_("print verbose messages."), 2},
526 {"uncompress", 'u', NULL, 0, N_("Uncompress data."), 2},
3286a4b4 527 {0, 0, 0, 0, 0, 0}
99fadbaa 528};
529
3286a4b4 530/* Print the version information. */
99fadbaa 531static void
3286a4b4 532print_version (FILE *stream, struct argp_state *state)
99fadbaa 533{
3286a4b4 534 fprintf (stream, "%s (%s) %s\n", program_name, PACKAGE_NAME, PACKAGE_VERSION);
99fadbaa 535}
3286a4b4 536void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
99fadbaa 537
1b024b4e 538static error_t
3286a4b4 539argp_parser (int key, char *arg, struct argp_state *state)
99fadbaa 540{
d5a32255 541 const char *p;
99fadbaa 542
3286a4b4 543 switch (key)
99fadbaa 544 {
3286a4b4
VS
545 case 'r':
546 root = arg;
547 return 0;
548
2cdc8995 549 case 'K':
ed746949
VS
550 if (strcmp (arg, "prompt") == 0)
551 {
552 char buf[1024];
10f0117b 553 grub_puts_ (N_("Enter ZFS password: "));
ed746949
VS
554 if (grub_password_get (buf, 1023))
555 {
556 grub_zfs_add_key ((grub_uint8_t *) buf, grub_strlen (buf), 1);
557 }
558 }
559 else
2cdc8995
VS
560 {
561 FILE *f;
562 ssize_t real_size;
ed746949 563 grub_uint8_t buf[1024];
bb338aaf 564 f = grub_util_fopen (arg, "rb");
2cdc8995
VS
565 if (!f)
566 {
9c4b5c13
VS
567 printf (_("%s: error:"), program_name);
568 printf (_("cannot open `%s': %s"), arg, strerror (errno));
569 printf ("\n");
2cdc8995
VS
570 return 0;
571 }
ed746949 572 real_size = fread (buf, 1, 1024, f);
151c19a4 573 fclose (f);
2cdc8995
VS
574 if (real_size < 0)
575 {
9c4b5c13
VS
576 printf (_("%s: error:"), program_name);
577 printf (_("cannot read `%s': %s"), arg, strerror (errno));
578 printf ("\n");
2cdc8995
VS
579 return 0;
580 }
ed746949 581 grub_zfs_add_key (buf, real_size, 0);
2cdc8995
VS
582 }
583 return 0;
584
41692608
VS
585 case 'C':
586 mount_crypt = 1;
587 return 0;
588
3286a4b4
VS
589 case 's':
590 skip = grub_strtoul (arg, &p, 0);
591 if (*p == 's')
592 skip <<= GRUB_DISK_SECTOR_BITS;
593 return 0;
594
595 case 'n':
596 leng = grub_strtoul (arg, &p, 0);
597 if (*p == 's')
598 leng <<= GRUB_DISK_SECTOR_BITS;
599 return 0;
600
601 case 'c':
602 num_disks = grub_strtoul (arg, NULL, 0);
603 if (num_disks < 1)
604 {
dfe3b247 605 fprintf (stderr, "%s", _("Invalid disk count.\n"));
3286a4b4
VS
606 argp_usage (state);
607 }
608 if (args_count != 0)
609 {
9c4b5c13
VS
610 /* TRANSLATORS: disk count is optional but if it's there it must
611 be before disk list. So please don't imply disk count as mandatory.
612 */
dfe3b247 613 fprintf (stderr, "%s", _("Disk count must precede disks list.\n"));
3286a4b4
VS
614 argp_usage (state);
615 }
616 return 0;
5ed20adc 617
3286a4b4
VS
618 case 'd':
619 debug_str = arg;
620 return 0;
99fadbaa 621
3286a4b4
VS
622 case 'v':
623 verbosity++;
624 return 0;
99fadbaa 625
7dc3c686
SJ
626 case 'u':
627 uncompress = 1;
628 return 0;
629
3286a4b4
VS
630 case ARGP_KEY_END:
631 if (args_count < num_disks)
632 {
dfe3b247 633 fprintf (stderr, "%s", _("No command is specified.\n"));
3286a4b4
VS
634 argp_usage (state);
635 }
636 if (args_count - 1 - num_disks < nparm)
637 {
dfe3b247 638 fprintf (stderr, "%s", _("Not enough parameters to command.\n"));
3286a4b4
VS
639 argp_usage (state);
640 }
641 return 0;
99fadbaa 642
3286a4b4
VS
643 case ARGP_KEY_ARG:
644 break;
99fadbaa 645
3286a4b4
VS
646 default:
647 return ARGP_ERR_UNKNOWN;
99fadbaa 648 }
649
3286a4b4 650 if (args_count < num_disks)
99fadbaa 651 {
3286a4b4 652 if (args_count == 0)
f725fa7c 653 images = xcalloc (num_disks, sizeof (images[0]));
27d1a67f 654 images[args_count] = grub_canonicalize_file_name (arg);
3286a4b4
VS
655 args_count++;
656 return 0;
99fadbaa 657 }
658
3286a4b4 659 if (args_count == num_disks)
99fadbaa 660 {
3286a4b4 661 if (!grub_strcmp (arg, "ls"))
5ed20adc 662 {
663 cmd = CMD_LS;
664 }
fdfde32a
VS
665 else if (!grub_strcmp (arg, "zfsinfo"))
666 {
667 cmd = CMD_ZFSINFO;
668 }
3286a4b4 669 else if (!grub_strcmp (arg, "cp"))
99fadbaa 670 {
671 cmd = CMD_CP;
5ed20adc 672 nparm = 2;
99fadbaa 673 }
3ca2b466
CW
674 else if (!grub_strcmp (arg, "cat"))
675 {
676 cmd = CMD_CAT;
677 nparm = 1;
678 }
3286a4b4 679 else if (!grub_strcmp (arg, "cmp"))
99fadbaa 680 {
681 cmd = CMD_CMP;
5ed20adc 682 nparm = 2;
99fadbaa 683 }
3286a4b4 684 else if (!grub_strcmp (arg, "hex"))
99fadbaa 685 {
686 cmd = CMD_HEX;
5ed20adc 687 nparm = 1;
688 }
3286a4b4 689 else if (!grub_strcmp (arg, "crc"))
5ed20adc 690 {
691 cmd = CMD_CRC;
692 nparm = 1;
99fadbaa 693 }
3286a4b4 694 else if (!grub_strcmp (arg, "blocklist"))
99fadbaa 695 {
696 cmd = CMD_BLOCKLIST;
5ed20adc 697 nparm = 1;
99fadbaa 698 }
77ba5392
VS
699 else if (!grub_strcmp (arg, "testload"))
700 {
701 cmd = CMD_TESTLOAD;
702 nparm = 1;
703 }
3be82e10
VS
704 else if (grub_strcmp (arg, "xnu_uuid") == 0)
705 {
706 cmd = CMD_XNU_UUID;
707 nparm = 0;
708 }
99fadbaa 709 else
710 {
3286a4b4
VS
711 fprintf (stderr, _("Invalid command %s.\n"), arg);
712 argp_usage (state);
99fadbaa 713 }
3286a4b4
VS
714 args_count++;
715 return 0;
716 }
99fadbaa 717
3286a4b4
VS
718 args[args_count - 1 - num_disks] = xstrdup (arg);
719 args_count++;
720 return 0;
721}
99fadbaa 722
3286a4b4
VS
723struct argp argp = {
724 options, argp_parser, N_("IMAGE_PATH COMMANDS"),
725 N_("Debug tool for filesystem driver."),
726 NULL, NULL, NULL
727};
728
729int
730main (int argc, char *argv[])
731{
1b024b4e
VS
732 const char *default_root;
733 char *alloc_root;
3286a4b4 734
ae5540d3 735 grub_util_host_init (&argc, &argv);
3286a4b4 736
f725fa7c 737 args = xcalloc (argc, sizeof (args[0]));
3286a4b4
VS
738
739 argp_parse (&argp, argc, argv, 0, 0, 0);
99fadbaa 740
99fadbaa 741 /* Initialize all modules. */
742 grub_init_all ();
41692608 743 grub_gcry_init_all ();
99fadbaa 744
99fadbaa 745 if (debug_str)
746 grub_env_set ("debug", debug_str);
747
5ed20adc 748 default_root = (num_disks == 1) ? "loop0" : "md0";
749 alloc_root = 0;
750 if (root)
751 {
752 if ((*root >= '0') && (*root <= '9'))
753 {
754 alloc_root = xmalloc (strlen (default_root) + strlen (root) + 2);
755
756 sprintf (alloc_root, "%s,%s", default_root, root);
757 root = alloc_root;
758 }
759 }
760 else
761 root = default_root;
762
763 grub_env_set ("root", root);
764
765 if (alloc_root)
766 free (alloc_root);
767
99fadbaa 768 /* Do it. */
1b024b4e 769 fstest (args_count - 1 - num_disks);
99fadbaa 770
771 /* Free resources. */
41692608 772 grub_gcry_fini_all ();
99fadbaa 773 grub_fini_all ();
774
99fadbaa 775 return 0;
776}