]>
Commit | Line | Data |
---|---|---|
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 | 50 | static grub_err_t |
1b024b4e | 51 | execute_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 |
62 | enum { |
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 | 76 | static grub_disk_addr_t skip, leng; |
7dc3c686 | 77 | static int uncompress = 0; |
99fadbaa | 78 | |
79 | static void | |
6c69e691 | 80 | read_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 | 177 | struct cp_hook_ctx |
99fadbaa | 178 | { |
179 | FILE *ff; | |
6c69e691 VS |
180 | const char *dest; |
181 | }; | |
99fadbaa | 182 | |
6c69e691 VS |
183 | static int |
184 | cp_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 |
199 | static void |
200 | cmd_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 | ||
218 | static int | |
219 | cat_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 |
233 | static void |
234 | cmd_cat (char *src) | |
235 | { | |
6c69e691 VS |
236 | read_file (src, cat_hook, 0); |
237 | } | |
3ca2b466 | 238 | |
6c69e691 VS |
239 | static int |
240 | cmp_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 | 269 | static void |
270 | cmd_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 |
335 | static int |
336 | hex_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 | 342 | static void |
343 | cmd_hex (char *pathname) | |
344 | { | |
6c69e691 VS |
345 | read_file (pathname, hex_hook, 0); |
346 | } | |
99fadbaa | 347 | |
6c69e691 VS |
348 | static int |
349 | crc_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 | ||
357 | static void | |
5ed20adc | 358 | cmd_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 | 370 | static const char *root = NULL; |
3286a4b4 VS |
371 | static int args_count = 0; |
372 | static int nparm = 0; | |
373 | static int num_disks = 1; | |
374 | static char **images = NULL; | |
375 | static int cmd = 0; | |
376 | static char *debug_str = NULL; | |
377 | static char **args = NULL; | |
41692608 | 378 | static int mount_crypt = 0; |
3286a4b4 | 379 | |
5ed20adc | 380 | static void |
1b024b4e | 381 | fstest (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 |
505 | static 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 | 531 | static void |
3286a4b4 | 532 | print_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 | 536 | void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version; |
99fadbaa | 537 | |
1b024b4e | 538 | static error_t |
3286a4b4 | 539 | argp_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 |
723 | struct argp argp = { |
724 | options, argp_parser, N_("IMAGE_PATH COMMANDS"), | |
725 | N_("Debug tool for filesystem driver."), | |
726 | NULL, NULL, NULL | |
727 | }; | |
728 | ||
729 | int | |
730 | main (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 | } |