2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 1999,2000,2001,2002,2003,2004,2009 Free Software Foundation, Inc.
4 * Copyright 2008 Sun Microsystems, 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/>.
20 #include <grub/zfs/zfs.h>
21 #include <grub/device.h>
22 #include <grub/file.h>
23 #include <grub/command.h>
24 #include <grub/extcmd.h>
25 #include <grub/misc.h>
29 #include <grub/i18n.h>
31 GRUB_MOD_LICENSE ("GPLv3+");
38 for (i
= 0; i
< n
; i
++)
43 print_state (char *nvlist
, int tab
)
49 grub_printf ("State: ");
51 if (grub_zfs_nvlist_lookup_uint64 (nvlist
, ZPOOL_CONFIG_REMOVED
, &ival
))
53 grub_printf ("removed ");
57 if (grub_zfs_nvlist_lookup_uint64 (nvlist
, ZPOOL_CONFIG_FAULTED
, &ival
))
59 grub_printf ("faulted ");
63 if (grub_zfs_nvlist_lookup_uint64 (nvlist
, ZPOOL_CONFIG_OFFLINE
, &ival
))
65 grub_printf ("offline ");
69 if (grub_zfs_nvlist_lookup_uint64 (nvlist
, ZPOOL_CONFIG_FAULTED
, &ival
))
70 grub_printf ("degraded ");
73 grub_printf ("online");
80 print_vdev_info (char *nvlist
, int tab
)
84 type
= grub_zfs_nvlist_lookup_string (nvlist
, ZPOOL_CONFIG_TYPE
);
89 grub_printf ("Incorrect VDEV: no type available\n");
93 if (grub_strcmp (type
, VDEV_TYPE_DISK
) == 0)
100 grub_printf ("Leaf VDEV\n");
102 print_state (nvlist
, tab
);
105 grub_zfs_nvlist_lookup_string (nvlist
, ZPOOL_CONFIG_PHYS_PATH
);
108 grub_printf ("Bootpath: unavailable\n");
110 grub_printf ("Bootpath: %s\n", bootpath
);
112 path
= grub_zfs_nvlist_lookup_string (nvlist
, "path");
115 grub_printf ("Path: unavailable\n");
117 grub_printf ("Path: %s\n", path
);
119 devid
= grub_zfs_nvlist_lookup_string (nvlist
, ZPOOL_CONFIG_DEVID
);
122 grub_printf ("Devid: unavailable\n");
124 grub_printf ("Devid: %s\n", devid
);
125 grub_free (bootpath
);
128 return GRUB_ERR_NONE
;
131 if (grub_strcmp (type
, VDEV_TYPE_MIRROR
) == 0)
135 nelm
= grub_zfs_nvlist_lookup_nvlist_array_get_nelm
136 (nvlist
, ZPOOL_CONFIG_CHILDREN
);
141 grub_printf ("Incorrect mirror VDEV\n");
142 return GRUB_ERR_NONE
;
144 grub_printf ("Mirror VDEV with %d children\n", nelm
);
145 print_state (nvlist
, tab
);
146 for (i
= 0; i
< nelm
; i
++)
150 child
= grub_zfs_nvlist_lookup_nvlist_array
151 (nvlist
, ZPOOL_CONFIG_CHILDREN
, i
);
156 grub_printf ("Mirror VDEV element %d isn't correct\n", i
);
160 grub_printf ("Mirror VDEV element %d:\n", i
);
161 print_vdev_info (child
, tab
+ 1);
165 return GRUB_ERR_NONE
;
169 grub_printf ("Unknown VDEV type: %s\n", type
);
171 return GRUB_ERR_NONE
;
175 get_bootpath (char *nvlist
, char **bootpath
, char **devid
)
179 type
= grub_zfs_nvlist_lookup_string (nvlist
, ZPOOL_CONFIG_TYPE
);
184 if (grub_strcmp (type
, VDEV_TYPE_DISK
) == 0)
186 *bootpath
= grub_zfs_nvlist_lookup_string (nvlist
,
187 ZPOOL_CONFIG_PHYS_PATH
);
188 *devid
= grub_zfs_nvlist_lookup_string (nvlist
, ZPOOL_CONFIG_DEVID
);
189 if (!*bootpath
|| !*devid
)
191 grub_free (*bootpath
);
196 return GRUB_ERR_NONE
;
199 if (grub_strcmp (type
, VDEV_TYPE_MIRROR
) == 0)
203 nelm
= grub_zfs_nvlist_lookup_nvlist_array_get_nelm
204 (nvlist
, ZPOOL_CONFIG_CHILDREN
);
206 for (i
= 0; i
< nelm
; i
++)
210 child
= grub_zfs_nvlist_lookup_nvlist_array (nvlist
,
211 ZPOOL_CONFIG_CHILDREN
,
214 get_bootpath (child
, bootpath
, devid
);
218 if (*bootpath
&& *devid
)
219 return GRUB_ERR_NONE
;
223 return GRUB_ERR_NONE
;
226 static char *poolstates
[] = {
227 [POOL_STATE_ACTIVE
] = "active",
228 [POOL_STATE_EXPORTED
] = "exported",
229 [POOL_STATE_DESTROYED
] = "destroyed",
230 [POOL_STATE_SPARE
] = "reserved for hot spare",
231 [POOL_STATE_L2CACHE
] = "level 2 ARC device",
232 [POOL_STATE_UNINITIALIZED
] = "uninitialized",
233 [POOL_STATE_UNAVAIL
] = "unavailable",
234 [POOL_STATE_POTENTIALLY_ACTIVE
] = "potentially active"
238 grub_cmd_zfsinfo (grub_command_t cmd
__attribute__ ((unused
)), int argc
,
248 grub_uint64_t pool_state
;
252 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "device name required");
254 if (args
[0][0] == '(' && args
[0][grub_strlen (args
[0]) - 1] == ')')
256 devname
= grub_strdup (args
[0] + 1);
258 devname
[grub_strlen (devname
) - 1] = 0;
261 devname
= grub_strdup (args
[0]);
265 dev
= grub_device_open (devname
);
270 err
= grub_zfs_fetch_nvlist (dev
, &nvlist
);
272 grub_device_close (dev
);
277 poolname
= grub_zfs_nvlist_lookup_string (nvlist
, ZPOOL_CONFIG_POOL_NAME
);
279 grub_printf ("Pool name: unavailable\n");
281 grub_printf ("Pool name: %s\n", poolname
);
284 grub_zfs_nvlist_lookup_uint64 (nvlist
, ZPOOL_CONFIG_POOL_GUID
, &guid
);
286 grub_printf ("Pool GUID: unavailable\n");
288 grub_printf ("Pool GUID: %016llx\n", (long long unsigned) guid
);
290 found
= grub_zfs_nvlist_lookup_uint64 (nvlist
, ZPOOL_CONFIG_POOL_STATE
,
293 grub_printf ("Unable to retrieve pool state\n");
294 else if (pool_state
>= ARRAY_SIZE (poolstates
))
295 grub_printf ("Unrecognized pool state\n");
297 grub_printf ("Pool state: %s\n", poolstates
[pool_state
]);
299 nv
= grub_zfs_nvlist_lookup_nvlist (nvlist
, ZPOOL_CONFIG_VDEV_TREE
);
302 grub_printf ("No vdev tree available\n");
304 print_vdev_info (nv
, 1);
309 return GRUB_ERR_NONE
;
313 grub_cmd_zfs_bootfs (grub_command_t cmd
__attribute__ ((unused
)), int argc
,
321 char *bootpath
= 0, *devid
= 0;
325 grub_uint64_t mdnobj
;
328 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "filesystem name required");
330 devname
= grub_file_get_device_name (args
[0]);
334 dev
= grub_device_open (devname
);
339 err
= grub_zfs_fetch_nvlist (dev
, &nvlist
);
341 fsname
= grub_strchr (args
[0], ')');
348 err
= grub_zfs_getmdnobj (dev
, fsname
, &mdnobj
);
350 grub_device_close (dev
);
355 poolname
= grub_zfs_nvlist_lookup_string (nvlist
, ZPOOL_CONFIG_POOL_NAME
);
359 grub_error (GRUB_ERR_BAD_FS
, "No poolname found");
363 nv
= grub_zfs_nvlist_lookup_nvlist (nvlist
, ZPOOL_CONFIG_VDEV_TREE
);
366 get_bootpath (nv
, &bootpath
, &devid
);
371 bootfs
= grub_xasprintf ("zfs-bootfs=%s/%llu%s%s%s%s%s%s",
372 poolname
, (unsigned long long) mdnobj
,
373 bootpath
? ",bootpath=\"" : "",
375 bootpath
? "\"" : "",
376 devid
? ",diskdevid=\"" : "",
382 grub_env_set (args
[1], bootfs
);
384 grub_printf ("%s\n", bootfs
);
387 grub_free (poolname
);
388 grub_free (bootpath
);
391 return GRUB_ERR_NONE
;
394 static const struct grub_arg_option options
[] =
396 {"raw", 'r', 0, N_("Assume input is raw."), 0, 0},
397 {"hex", 'h', 0, N_("Assume input is hex."), 0, 0},
398 {"passphrase", 'p', 0, N_("Assume input is passphrase."), 0, 0},
403 grub_cmd_zfs_key (grub_extcmd_context_t ctxt
, int argc
, char **args
)
405 grub_uint8_t buf
[1024];
406 grub_ssize_t real_size
;
411 file
= grub_file_open (args
[0]);
414 real_size
= grub_file_read (file
, buf
, 1024);
418 if (ctxt
->state
[0].set
419 || (argc
> 0 && !ctxt
->state
[1].set
&& !ctxt
->state
[2].set
))
422 if (real_size
< GRUB_ZFS_MAX_KEYLEN
)
423 grub_memset (buf
+ real_size
, 0, GRUB_ZFS_MAX_KEYLEN
- real_size
);
424 err
= grub_zfs_add_key (buf
);
427 return GRUB_ERR_NONE
;
430 if (ctxt
->state
[1].set
)
434 if (real_size
< 2 * GRUB_ZFS_MAX_KEYLEN
)
435 grub_memset (buf
+ real_size
, '0', 2 * GRUB_ZFS_MAX_KEYLEN
- real_size
);
436 for (i
= 0; i
< GRUB_ZFS_MAX_KEYLEN
; i
++)
438 char c1
= grub_tolower (buf
[2 * i
]) - '0';
439 char c2
= grub_tolower (buf
[2 * i
+ 1]) - '0';
441 c1
+= '0' - 'a' + 10;
443 c2
+= '0' - 'a' + 10;
444 buf
[i
] = (c1
<< 4) | c2
;
446 err
= grub_zfs_add_key (buf
);
449 return GRUB_ERR_NONE
;
451 return GRUB_ERR_NONE
;
454 static grub_command_t cmd_info
, cmd_bootfs
;
455 static grub_extcmd_t cmd_key
;
457 GRUB_MOD_INIT (zfsinfo
)
459 cmd_info
= grub_register_command ("zfsinfo", grub_cmd_zfsinfo
,
461 "Print ZFS info about DEVICE.");
462 cmd_key
= grub_register_extcmd ("zfskey", grub_cmd_zfs_key
, 0,
463 "zfskey [-h|-p|-r] [FILE]",
464 "Import ZFS wrapping key stored in FILE.",
466 cmd_bootfs
= grub_register_command ("zfs-bootfs", grub_cmd_zfs_bootfs
,
467 "zfs-bootfs FILESYSTEM [VARIABLE]",
468 "Print ZFS-BOOTFSOBJ or set it to VARIABLE");
471 GRUB_MOD_FINI (zfsinfo
)
473 grub_unregister_command (cmd_info
);
474 grub_unregister_command (cmd_bootfs
);
475 grub_unregister_extcmd (cmd_key
);