1 /* grub-fstest.c - debug tool for filesystem driver */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2008 Free Software Foundation, Inc.
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.
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.
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/>.
21 #include <grub/types.h>
22 #include <grub/util/misc.h>
23 #include <grub/misc.h>
24 #include <grub/device.h>
25 #include <grub/disk.h>
26 #include <grub/file.h>
29 #include <grub/term.h>
31 #include <grub/normal.h>
32 #include <grub/raid.h>
33 #include <grub/lib/hexdump.h>
34 #include <grub/lib/crc.h>
36 #include <grub_fstest_init.h>
57 grub_term_get_current_input (void)
63 grub_term_get_current_output (void)
74 static struct grub_command cmd_loopback
;
75 static struct grub_command cmd_blocklist
;
76 static struct grub_command cmd_ls
;
79 grub_register_command (const char *name
,
80 grub_err_t (*func
) (struct grub_arg_list
* state
,
81 int argc
, char **args
),
83 const char *summary
__attribute__ ((unused
)),
84 const char *description
__attribute__ ((unused
)),
85 const struct grub_arg_option
*options
)
87 grub_command_t cmd
= 0;
89 if (!grub_strcmp (name
, "loopback"))
91 else if (!grub_strcmp (name
, "blocklist"))
93 else if (!grub_strcmp (name
, "ls"))
100 cmd
->options
= options
;
106 execute_command (grub_command_t cmd
, int n
, char **args
)
110 struct grub_arg_list
*state
;
111 struct grub_arg_option
*parser
;
112 char **parsed_arglist
;
115 /* Count the amount of options the command has. */
116 parser
= (struct grub_arg_option
*) cmd
->options
;
117 while (parser
&& (parser
++)->doc
)
120 /* Set up the option state. */
121 state
= grub_malloc (sizeof (struct grub_arg_list
) * maxargs
);
122 grub_memset (state
, 0, sizeof (struct grub_arg_list
) * maxargs
);
124 /* Start the command. */
125 if (!(cmd
->flags
& GRUB_COMMAND_FLAG_NO_ARG_PARSE
))
127 if (grub_arg_parse (cmd
, n
, args
, state
, &parsed_arglist
, &numargs
))
128 ret
= (cmd
->func
) (state
, numargs
, parsed_arglist
);
131 ret
= (cmd
->func
) (state
, n
, args
);
139 grub_unregister_command (const char *name
__attribute__ ((unused
)))
148 #define CMD_BLOCKLIST 7
150 #define BUF_SIZE 32256
152 static grub_off_t skip
, leng
;
155 read_file (char *pathname
, int (*hook
) (grub_off_t ofs
, char *buf
, int len
))
157 static char buf
[BUF_SIZE
];
161 if ((pathname
[0] == '-') && (pathname
[1] == 0))
165 dev
= grub_device_open (0);
166 if ((! dev
) || (! dev
->disk
))
167 grub_util_error ("Can\'t open device.");
169 grub_util_info ("total sectors : %lld.",
170 (unsigned long long) dev
->disk
->total_sectors
);
173 leng
= (dev
->disk
->total_sectors
<< GRUB_DISK_SECTOR_BITS
) - skip
;
179 len
= (leng
> BUF_SIZE
) ? BUF_SIZE
: leng
;
181 if (grub_disk_read (dev
->disk
, 0, skip
, len
, buf
))
182 grub_util_error ("Disk read fails at offset %lld, length %d.",
185 if (hook (skip
, buf
, len
))
192 grub_device_close (dev
);
196 file
= grub_file_open (pathname
);
199 grub_util_error ("cannot open file %s.", pathname
);
203 grub_util_info ("file size : %lld.", (unsigned long long) file
->size
);
205 if (skip
> file
->size
)
207 grub_util_error ("invalid skip value %d.");
212 len
= file
->size
- skip
;
213 if ((leng
) && (leng
< len
))
222 sz
= grub_file_read (file
, buf
, (len
> BUF_SIZE
) ? BUF_SIZE
: len
);
225 grub_util_error ("read error at offset %llu.", ofs
);
229 if ((sz
== 0) || (hook (ofs
, buf
, sz
)))
236 grub_file_close (file
);
240 cmd_cp (char *src
, char *dest
)
244 auto int cp_hook (grub_off_t ofs
, char *buf
, int len
);
245 int cp_hook (grub_off_t ofs
, char *buf
, int len
)
249 if ((int) fwrite (buf
, 1, len
, ff
) != len
)
251 grub_util_error ("write error.");
258 ff
= fopen (dest
, "wb");
261 grub_util_error ("open error.");
264 read_file (src
, cp_hook
);
269 cmd_cmp (char *src
, char *dest
)
272 static char buf_1
[BUF_SIZE
];
274 auto int cmp_hook (grub_off_t ofs
, char *buf
, int len
);
275 int cmp_hook (grub_off_t ofs
, char *buf
, int len
)
277 if ((int) fread (buf_1
, 1, len
, ff
) != len
)
279 grub_util_error ("read error at offset %llu.", ofs
);
283 if (grub_memcmp (buf
, buf_1
, len
))
287 for (i
= 0; i
< len
; i
++, ofs
++)
288 if (buf_1
[i
] != buf
[i
])
290 grub_util_error ("compare fail at offset %llu.", ofs
);
297 ff
= fopen (dest
, "rb");
300 grub_util_error ("open error.");
304 if ((skip
) && (fseeko (ff
, skip
, SEEK_SET
)))
305 grub_util_error ("seek error.");
307 read_file (src
, cmp_hook
);
312 cmd_hex (char *pathname
)
314 auto int hex_hook (grub_off_t ofs
, char *buf
, int len
);
315 int hex_hook (grub_off_t ofs
, char *buf
, int len
)
317 hexdump (ofs
, buf
, len
);
321 read_file (pathname
, hex_hook
);
325 cmd_crc (char *pathname
)
327 grub_uint32_t crc
= 0;
329 auto int crc_hook (grub_off_t ofs
, char *buf
, int len
);
330 int crc_hook (grub_off_t ofs
, char *buf
, int len
)
334 crc
= grub_getcrc32 (crc
, buf
, len
);
338 read_file (pathname
, crc_hook
);
339 printf ("%08x\n", crc
);
343 fstest (char **images
, int num_disks
, int cmd
, int n
, char **args
)
347 char *argv
[3] = { "-p", loop_name
, host_file
};
350 for (i
= 0; i
< num_disks
; i
++)
352 if (grub_strlen (images
[i
]) + 7 > sizeof (host_file
))
353 grub_util_error ("Pathname %s too long.", images
[i
]);
355 grub_sprintf (loop_name
, "loop%d", i
);
356 grub_sprintf (host_file
, "(host)%s", images
[i
]);
358 if (execute_command (&cmd_loopback
, 3, argv
))
359 grub_util_error ("loopback command fails.");
366 execute_command (&cmd_ls
, n
, args
);
369 cmd_cp (args
[0], args
[1]);
372 cmd_cmp (args
[0], args
[1]);
381 execute_command (&cmd_blocklist
, n
, args
);
387 for (i
= 0; i
< num_disks
; i
++)
389 grub_sprintf (loop_name
, "loop%d", i
);
390 execute_command (&cmd_loopback
, 2, argv
);
394 static struct option options
[] = {
395 {"root", required_argument
, 0, 'r'},
396 {"skip", required_argument
, 0, 's'},
397 {"length", required_argument
, 0, 'n'},
398 {"diskcount", required_argument
, 0, 'c'},
399 {"debug", required_argument
, 0, 'd'},
400 {"help", no_argument
, 0, 'h'},
401 {"version", no_argument
, 0, 'V'},
402 {"verbose", no_argument
, 0, 'v'},
410 fprintf (stderr
, "Try ``grub-fstest --help'' for more information.\n");
413 Usage: grub-fstest [OPTION]... IMAGE_PATH COMMANDS\n\
415 Debug tool for filesystem driver.\n\
417 ls PATH list files in PATH\n\
418 cp FILE LOCAL copy FILE to local file LOCAL\n\
419 cmp FILE LOCAL compare FILE with local file LOCAL\n\
420 hex FILE Hex dump FILE\n\
421 crc FILE Get crc32 checksum of FILE\n\
422 blocklist FILE display blocklist of FILE\n\
424 -r, --root=DEVICE_NAME set root device\n\
425 -s, --skip=N skip N bytes from output file\n\
426 -n, --length=N handle N bytes in output file\n\
427 -c, --diskcount=N N input files\n\
428 -d, --debug=S Set debug environment variable\n\
429 -h, --help display this message and exit\n\
430 -V, --version print version information and exit\n\
431 -v, --verbose print verbose messages\n\
433 Report bugs to <%s>.\n", PACKAGE_BUGREPORT
);
439 main (int argc
, char *argv
[])
441 char *debug_str
= 0, *root
= 0, *default_root
, *alloc_root
;
442 int i
, cmd
, num_opts
, image_index
, num_disks
= 1;
444 progname
= "grub-fstest";
446 /* Find the first non option entry. */
447 for (num_opts
= 1; num_opts
< argc
; num_opts
++)
448 if (argv
[num_opts
][0] == '-')
450 if ((argv
[num_opts
][2] == 0) && (num_opts
< argc
- 1) &&
451 ((argv
[num_opts
][1] == 'r') ||
452 (argv
[num_opts
][1] == 's') ||
453 (argv
[num_opts
][1] == 'n') ||
454 (argv
[num_opts
][1] == 'c') ||
455 (argv
[num_opts
][1] == 'd')))
461 /* Check for options. */
464 int c
= getopt_long (num_opts
, argv
, "r:s:n:c:d:hVv", options
, 0);
477 skip
= grub_strtoul (optarg
, &p
, 0);
479 skip
<<= GRUB_DISK_SECTOR_BITS
;
483 leng
= grub_strtoul (optarg
, &p
, 0);
485 leng
<<= GRUB_DISK_SECTOR_BITS
;
489 num_disks
= grub_strtoul (optarg
, NULL
, 0);
492 fprintf (stderr
, "Invalid disk count.\n");
506 printf ("%s (%s) %s\n", progname
, PACKAGE_NAME
, PACKAGE_VERSION
);
520 if (optind
+ num_disks
- 1 >= argc
)
522 fprintf (stderr
, "Not enough pathname.\n");
526 image_index
= optind
;
527 for (i
= 0; i
< num_disks
; i
++, optind
++)
528 if (argv
[optind
][0] != '/')
530 fprintf (stderr
, "Must use absolute path.\n");
539 if (!grub_strcmp (argv
[optind
], "ls"))
543 else if (!grub_strcmp (argv
[optind
], "cp"))
548 else if (!grub_strcmp (argv
[optind
], "cmp"))
553 else if (!grub_strcmp (argv
[optind
], "hex"))
558 else if (!grub_strcmp (argv
[optind
], "crc"))
563 else if (!grub_strcmp (argv
[optind
], "blocklist"))
570 fprintf (stderr
, "Invalid command %s.\n", argv
[optind
]);
574 if (optind
+ 1 + nparm
> argc
)
576 fprintf (stderr
, "Invalid parameter for command %s.\n",
585 fprintf (stderr
, "No command is specified.\n");
589 /* Initialize all modules. */
593 grub_env_set ("debug", debug_str
);
595 default_root
= (num_disks
== 1) ? "loop0" : "md0";
599 if ((*root
>= '0') && (*root
<= '9'))
601 alloc_root
= xmalloc (strlen (default_root
) + strlen (root
) + 2);
603 sprintf (alloc_root
, "%s,%s", default_root
, root
);
610 grub_env_set ("root", root
);
616 fstest (argv
+ image_index
, num_disks
, cmd
, argc
- optind
, argv
+ optind
);
618 /* Free resources. */