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>
29 GRUB_MOD_LICENSE ("GPLv3+");
36 for (i
= 0; i
< n
; i
++)
41 print_state (char *nvlist
, int tab
)
47 grub_printf ("State: ");
49 if (grub_zfs_nvlist_lookup_uint64 (nvlist
, ZPOOL_CONFIG_REMOVED
, &ival
))
51 grub_printf ("removed ");
55 if (grub_zfs_nvlist_lookup_uint64 (nvlist
, ZPOOL_CONFIG_FAULTED
, &ival
))
57 grub_printf ("faulted ");
61 if (grub_zfs_nvlist_lookup_uint64 (nvlist
, ZPOOL_CONFIG_OFFLINE
, &ival
))
63 grub_printf ("offline ");
67 if (grub_zfs_nvlist_lookup_uint64 (nvlist
, ZPOOL_CONFIG_FAULTED
, &ival
))
68 grub_printf ("degraded ");
71 grub_printf ("online");
78 print_vdev_info (char *nvlist
, int tab
)
82 type
= grub_zfs_nvlist_lookup_string (nvlist
, ZPOOL_CONFIG_TYPE
);
87 grub_printf ("Incorrect VDEV: no type available\n");
91 if (grub_strcmp (type
, VDEV_TYPE_DISK
) == 0)
98 grub_printf ("Leaf VDEV\n");
100 print_state (nvlist
, tab
);
103 grub_zfs_nvlist_lookup_string (nvlist
, ZPOOL_CONFIG_PHYS_PATH
);
106 grub_printf ("Bootpath: unavailable\n");
108 grub_printf ("Bootpath: %s\n", bootpath
);
110 path
= grub_zfs_nvlist_lookup_string (nvlist
, "path");
113 grub_printf ("Path: unavailable\n");
115 grub_printf ("Path: %s\n", path
);
117 devid
= grub_zfs_nvlist_lookup_string (nvlist
, ZPOOL_CONFIG_DEVID
);
120 grub_printf ("Devid: unavailable\n");
122 grub_printf ("Devid: %s\n", devid
);
123 grub_free (bootpath
);
126 return GRUB_ERR_NONE
;
129 if (grub_strcmp (type
, VDEV_TYPE_MIRROR
) == 0)
133 nelm
= grub_zfs_nvlist_lookup_nvlist_array_get_nelm
134 (nvlist
, ZPOOL_CONFIG_CHILDREN
);
139 grub_printf ("Incorrect mirror VDEV\n");
140 return GRUB_ERR_NONE
;
142 grub_printf ("Mirror VDEV with %d children\n", nelm
);
143 print_state (nvlist
, tab
);
145 for (i
= 0; i
< nelm
; i
++)
149 child
= grub_zfs_nvlist_lookup_nvlist_array
150 (nvlist
, ZPOOL_CONFIG_CHILDREN
, i
);
155 grub_printf ("Mirror VDEV element %d isn't correct\n", i
);
159 grub_printf ("Mirror VDEV element %d:\n", i
);
160 print_vdev_info (child
, tab
+ 1);
167 grub_printf ("Unknown VDEV type: %s\n", type
);
169 return GRUB_ERR_NONE
;
173 get_bootpath (char *nvlist
, char **bootpath
, char **devid
)
177 type
= grub_zfs_nvlist_lookup_string (nvlist
, ZPOOL_CONFIG_TYPE
);
182 if (grub_strcmp (type
, VDEV_TYPE_DISK
) == 0)
184 *bootpath
= grub_zfs_nvlist_lookup_string (nvlist
,
185 ZPOOL_CONFIG_PHYS_PATH
);
186 *devid
= grub_zfs_nvlist_lookup_string (nvlist
, ZPOOL_CONFIG_DEVID
);
187 if (!*bootpath
|| !*devid
)
189 grub_free (*bootpath
);
194 return GRUB_ERR_NONE
;
197 if (grub_strcmp (type
, VDEV_TYPE_MIRROR
) == 0)
201 nelm
= grub_zfs_nvlist_lookup_nvlist_array_get_nelm
202 (nvlist
, ZPOOL_CONFIG_CHILDREN
);
204 for (i
= 0; i
< nelm
; i
++)
208 child
= grub_zfs_nvlist_lookup_nvlist_array (nvlist
,
209 ZPOOL_CONFIG_CHILDREN
,
212 get_bootpath (child
, bootpath
, devid
);
216 if (*bootpath
&& *devid
)
217 return GRUB_ERR_NONE
;
221 return GRUB_ERR_NONE
;
224 static char *poolstates
[] = {
225 [POOL_STATE_ACTIVE
] = "active",
226 [POOL_STATE_EXPORTED
] = "exported",
227 [POOL_STATE_DESTROYED
] = "destroyed",
228 [POOL_STATE_SPARE
] = "reserved for hot spare",
229 [POOL_STATE_L2CACHE
] = "level 2 ARC device",
230 [POOL_STATE_UNINITIALIZED
] = "uninitialized",
231 [POOL_STATE_UNAVAIL
] = "unavailable",
232 [POOL_STATE_POTENTIALLY_ACTIVE
] = "potentially active"
236 grub_cmd_zfsinfo (grub_command_t cmd
__attribute__ ((unused
)), int argc
,
246 grub_uint64_t pool_state
;
250 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "device name required");
252 if (args
[0][0] == '(' && args
[0][grub_strlen (args
[0]) - 1] == ')')
254 devname
= grub_strdup (args
[0] + 1);
256 devname
[grub_strlen (devname
) - 1] = 0;
259 devname
= grub_strdup (args
[0]);
263 dev
= grub_device_open (devname
);
268 err
= grub_zfs_fetch_nvlist (dev
, &nvlist
);
270 grub_device_close (dev
);
275 poolname
= grub_zfs_nvlist_lookup_string (nvlist
, ZPOOL_CONFIG_POOL_NAME
);
277 grub_printf ("Pool name: unavailable\n");
279 grub_printf ("Pool name: %s\n", poolname
);
282 grub_zfs_nvlist_lookup_uint64 (nvlist
, ZPOOL_CONFIG_POOL_GUID
, &guid
);
284 grub_printf ("Pool GUID: unavailable\n");
286 grub_printf ("Pool GUID: %016llx\n", (long long unsigned) guid
);
288 found
= grub_zfs_nvlist_lookup_uint64 (nvlist
, ZPOOL_CONFIG_POOL_STATE
,
291 grub_printf ("Unable to retrieve pool state\n");
292 else if (pool_state
>= ARRAY_SIZE (poolstates
))
293 grub_printf ("Unrecognized pool state\n");
295 grub_printf ("Pool state: %s\n", poolstates
[pool_state
]);
297 nv
= grub_zfs_nvlist_lookup_nvlist (nvlist
, ZPOOL_CONFIG_VDEV_TREE
);
300 grub_printf ("No vdev tree available\n");
302 print_vdev_info (nv
, 1);
307 return GRUB_ERR_NONE
;
311 grub_cmd_zfs_bootfs (grub_command_t cmd
__attribute__ ((unused
)), int argc
,
319 char *bootpath
= 0, *devid
= 0;
323 grub_uint64_t mdnobj
;
326 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "filesystem name required");
328 devname
= grub_file_get_device_name (args
[0]);
332 dev
= grub_device_open (devname
);
337 err
= grub_zfs_fetch_nvlist (dev
, &nvlist
);
339 fsname
= grub_strchr (args
[0], ')');
346 err
= grub_zfs_getmdnobj (dev
, fsname
, &mdnobj
);
348 grub_device_close (dev
);
353 poolname
= grub_zfs_nvlist_lookup_string (nvlist
, ZPOOL_CONFIG_POOL_NAME
);
357 grub_error (GRUB_ERR_BAD_FS
, "No poolname found");
361 nv
= grub_zfs_nvlist_lookup_nvlist (nvlist
, ZPOOL_CONFIG_VDEV_TREE
);
364 get_bootpath (nv
, &bootpath
, &devid
);
369 bootfs
= grub_xasprintf ("zfs-bootfs=%s/%llu%s%s%s%s%s%s",
370 poolname
, (unsigned long long) mdnobj
,
371 bootpath
? ",bootpath=\"" : "",
373 bootpath
? "\"" : "",
374 devid
? ",diskdevid=\"" : "",
380 grub_env_set (args
[1], bootfs
);
382 grub_printf ("%s\n", bootfs
);
385 grub_free (poolname
);
386 grub_free (bootpath
);
389 return GRUB_ERR_NONE
;
393 static grub_command_t cmd_info
, cmd_bootfs
;
395 GRUB_MOD_INIT (zfsinfo
)
397 cmd_info
= grub_register_command ("zfsinfo", grub_cmd_zfsinfo
,
399 "Print ZFS info about DEVICE.");
400 cmd_bootfs
= grub_register_command ("zfs-bootfs", grub_cmd_zfs_bootfs
,
401 "zfs-bootfs FILESYSTEM [VARIABLE]",
402 "Print ZFS-BOOTFSOBJ or set it to VARIABLE");
405 GRUB_MOD_FINI (zfsinfo
)
407 grub_unregister_command (cmd_info
);
408 grub_unregister_command (cmd_bootfs
);