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/misc.h>
34 for (i
= 0; i
< n
; i
++)
39 print_state (char *nvlist
, int tab
)
45 grub_printf ("State: ");
47 if (grub_zfs_nvlist_lookup_uint64 (nvlist
, ZPOOL_CONFIG_REMOVED
, &ival
))
49 grub_printf ("removed ");
53 if (grub_zfs_nvlist_lookup_uint64 (nvlist
, ZPOOL_CONFIG_FAULTED
, &ival
))
55 grub_printf ("faulted ");
59 if (grub_zfs_nvlist_lookup_uint64 (nvlist
, ZPOOL_CONFIG_OFFLINE
, &ival
))
61 grub_printf ("offline ");
65 if (grub_zfs_nvlist_lookup_uint64 (nvlist
, ZPOOL_CONFIG_FAULTED
, &ival
))
66 grub_printf ("degraded ");
69 grub_printf ("online");
76 print_vdev_info (char *nvlist
, int tab
)
80 type
= grub_zfs_nvlist_lookup_string (nvlist
, ZPOOL_CONFIG_TYPE
);
85 grub_printf ("Incorrect VDEV: no type available\n");
89 if (grub_strcmp (type
, VDEV_TYPE_DISK
) == 0)
96 grub_printf ("Leaf VDEV\n");
98 print_state (nvlist
, tab
);
101 grub_zfs_nvlist_lookup_string (nvlist
, ZPOOL_CONFIG_PHYS_PATH
);
104 grub_printf ("Bootpath: unavailable\n");
106 grub_printf ("Bootpath: %s\n", bootpath
);
108 path
= grub_zfs_nvlist_lookup_string (nvlist
, "path");
111 grub_printf ("Path: unavailable\n");
113 grub_printf ("Path: %s\n", path
);
115 devid
= grub_zfs_nvlist_lookup_string (nvlist
, ZPOOL_CONFIG_DEVID
);
118 grub_printf ("Devid: unavailable\n");
120 grub_printf ("Devid: %s\n", devid
);
121 grub_free (bootpath
);
124 return GRUB_ERR_NONE
;
127 if (grub_strcmp (type
, VDEV_TYPE_MIRROR
) == 0)
131 nelm
= grub_zfs_nvlist_lookup_nvlist_array_get_nelm
132 (nvlist
, ZPOOL_CONFIG_CHILDREN
);
137 grub_printf ("Incorrect mirror VDEV\n");
138 return GRUB_ERR_NONE
;
140 grub_printf ("Mirror VDEV with %d children\n", nelm
);
141 print_state (nvlist
, tab
);
143 for (i
= 0; i
< nelm
; i
++)
147 child
= grub_zfs_nvlist_lookup_nvlist_array
148 (nvlist
, ZPOOL_CONFIG_CHILDREN
, i
);
153 grub_printf ("Mirror VDEV element %d isn't correct\n", i
);
157 grub_printf ("Mirror VDEV element %d:\n", i
);
158 print_vdev_info (child
, tab
+ 1);
165 grub_printf ("Unknown VDEV type: %s\n", type
);
167 return GRUB_ERR_NONE
;
171 get_bootpath (char *nvlist
, char **bootpath
, char **devid
)
175 type
= grub_zfs_nvlist_lookup_string (nvlist
, ZPOOL_CONFIG_TYPE
);
180 if (grub_strcmp (type
, VDEV_TYPE_DISK
) == 0)
182 *bootpath
= grub_zfs_nvlist_lookup_string (nvlist
,
183 ZPOOL_CONFIG_PHYS_PATH
);
184 *devid
= grub_zfs_nvlist_lookup_string (nvlist
, ZPOOL_CONFIG_DEVID
);
185 if (!*bootpath
|| !*devid
)
187 grub_free (*bootpath
);
192 return GRUB_ERR_NONE
;
195 if (grub_strcmp (type
, VDEV_TYPE_MIRROR
) == 0)
199 nelm
= grub_zfs_nvlist_lookup_nvlist_array_get_nelm
200 (nvlist
, ZPOOL_CONFIG_CHILDREN
);
202 for (i
= 0; i
< nelm
; i
++)
206 child
= grub_zfs_nvlist_lookup_nvlist_array (nvlist
,
207 ZPOOL_CONFIG_CHILDREN
,
210 get_bootpath (child
, bootpath
, devid
);
214 if (*bootpath
&& *devid
)
215 return GRUB_ERR_NONE
;
219 return GRUB_ERR_NONE
;
222 static char *poolstates
[] = {
223 [POOL_STATE_ACTIVE
] = "active",
224 [POOL_STATE_EXPORTED
] = "exported",
225 [POOL_STATE_DESTROYED
] = "destroyed",
226 [POOL_STATE_SPARE
] = "reserved for hot spare",
227 [POOL_STATE_L2CACHE
] = "level 2 ARC device",
228 [POOL_STATE_UNINITIALIZED
] = "uninitialized",
229 [POOL_STATE_UNAVAIL
] = "unavailable",
230 [POOL_STATE_POTENTIALLY_ACTIVE
] = "potentially active"
234 grub_cmd_zfsinfo (grub_command_t cmd
__attribute__ ((unused
)), int argc
,
244 grub_uint64_t pool_state
;
248 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "device name required");
250 if (args
[0][0] == '(' && args
[0][grub_strlen (args
[0]) - 1] == ')')
252 devname
= grub_strdup (args
[0] + 1);
254 devname
[grub_strlen (devname
) - 1] = 0;
257 devname
= grub_strdup (args
[0]);
261 dev
= grub_device_open (devname
);
266 err
= grub_zfs_fetch_nvlist (dev
, &nvlist
);
268 grub_device_close (dev
);
273 poolname
= grub_zfs_nvlist_lookup_string (nvlist
, ZPOOL_CONFIG_POOL_NAME
);
275 grub_printf ("Pool name: unavailable\n");
277 grub_printf ("Pool name: %s\n", poolname
);
280 grub_zfs_nvlist_lookup_uint64 (nvlist
, ZPOOL_CONFIG_POOL_GUID
, &guid
);
282 grub_printf ("Pool GUID: unavailable\n");
284 grub_printf ("Pool GUID: %016llx\n", (long long unsigned) guid
);
286 found
= grub_zfs_nvlist_lookup_uint64 (nvlist
, ZPOOL_CONFIG_POOL_STATE
,
289 grub_printf ("Unable to retrieve pool state\n");
290 else if (pool_state
>= ARRAY_SIZE (poolstates
))
291 grub_printf ("Unrecognized pool state\n");
293 grub_printf ("Pool state: %s\n", poolstates
[pool_state
]);
295 nv
= grub_zfs_nvlist_lookup_nvlist (nvlist
, ZPOOL_CONFIG_VDEV_TREE
);
298 grub_printf ("No vdev tree available\n");
300 print_vdev_info (nv
, 1);
305 return GRUB_ERR_NONE
;
309 grub_cmd_zfs_bootfs (grub_command_t cmd
__attribute__ ((unused
)), int argc
,
317 char *bootpath
= 0, *devid
= 0;
321 grub_uint64_t mdnobj
;
324 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "filesystem name required");
326 devname
= grub_file_get_device_name (args
[0]);
330 dev
= grub_device_open (devname
);
335 err
= grub_zfs_fetch_nvlist (dev
, &nvlist
);
337 fsname
= grub_strchr (args
[0], ')');
344 err
= grub_zfs_getmdnobj (dev
, fsname
, &mdnobj
);
346 grub_device_close (dev
);
351 poolname
= grub_zfs_nvlist_lookup_string (nvlist
, ZPOOL_CONFIG_POOL_NAME
);
355 grub_error (GRUB_ERR_BAD_FS
, "No poolname found");
359 nv
= grub_zfs_nvlist_lookup_nvlist (nvlist
, ZPOOL_CONFIG_VDEV_TREE
);
362 get_bootpath (nv
, &bootpath
, &devid
);
367 bootfs
= grub_xasprintf ("zfs-bootfs=%s/%llu%s%s%s%s",
368 poolname
, (unsigned long long) mdnobj
,
369 bootpath
? ",bootpath=" : "",
371 devid
? ",diskdevid=" : "",
376 grub_env_set (args
[1], bootfs
);
378 grub_printf ("%s\n", bootfs
);
381 grub_free (poolname
);
382 grub_free (bootpath
);
385 return GRUB_ERR_NONE
;
389 static grub_command_t cmd_info
, cmd_bootfs
;
391 GRUB_MOD_INIT (zfsinfo
)
393 cmd_info
= grub_register_command ("zfsinfo", grub_cmd_zfsinfo
,
395 "Print ZFS info about DEVICE.");
396 cmd_bootfs
= grub_register_command ("zfs-bootfs", grub_cmd_zfs_bootfs
,
397 "zfs-bootfs FILESYSTEM [VARIABLE]",
398 "Print ZFS-BOOTFSOBJ or set it to VARIABLE");
401 GRUB_MOD_FINI (zfsinfo
)
403 grub_unregister_command (cmd_info
);
404 grub_unregister_command (cmd_bootfs
);