123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442 |
- /*
- * GRUB -- GRand Unified Bootloader
- * Copyright (C) 1999,2000,2001,2002,2003,2004,2009 Free Software Foundation, Inc.
- * Copyright 2008 Sun Microsystems, Inc.
- *
- * GRUB is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * GRUB is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
- */
- #include <grub/zfs/zfs.h>
- #include <grub/device.h>
- #include <grub/file.h>
- #include <grub/command.h>
- #include <grub/misc.h>
- #include <grub/mm.h>
- #include <grub/dl.h>
- #include <grub/env.h>
- #include <grub/i18n.h>
- GRUB_MOD_LICENSE ("GPLv3+");
- static inline void
- print_tabs (int n)
- {
- int i;
- for (i = 0; i < n; i++)
- grub_printf (" ");
- }
- static grub_err_t
- print_state (char *nvlist, int tab)
- {
- grub_uint64_t ival;
- int isok = 1;
- print_tabs (tab);
- if (grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_REMOVED, &ival))
- {
- grub_puts_ (N_("Virtual device is removed"));
- isok = 0;
- }
- if (grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_FAULTED, &ival))
- {
- grub_puts_ (N_("Virtual device is faulted"));
- isok = 0;
- }
- if (grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_OFFLINE, &ival))
- {
- grub_puts_ (N_("Virtual device is offline"));
- isok = 0;
- }
- if (grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_FAULTED, &ival))
- /* TRANSLATORS: degraded doesn't mean broken but that some of
- component are missing but virtual device as whole is still usable. */
- grub_puts_ (N_("Virtual device is degraded"));
- if (isok)
- grub_puts_ (N_("Virtual device is online"));
- grub_xputs ("\n");
- return GRUB_ERR_NONE;
- }
- static grub_err_t
- print_vdev_info (char *nvlist, int tab)
- {
- char *type = 0;
- type = grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_TYPE);
- if (!type)
- {
- print_tabs (tab);
- grub_puts_ (N_("Incorrect virtual device: no type available"));
- return grub_errno;
- }
- if (grub_strcmp (type, VDEV_TYPE_DISK) == 0)
- {
- char *bootpath = 0;
- char *path = 0;
- char *devid = 0;
- print_tabs (tab);
- /* TRANSLATORS: The virtual devices form a tree (in graph-theoretical
- sense). The nodes like mirror or raidz have children: member devices.
- The "real" devices which actually store data are called "leafs"
- (again borrowed from graph theory) and can be either disks
- (or partitions) or files. */
- grub_puts_ (N_("Leaf virtual device (file or disk)"));
- print_state (nvlist, tab);
- bootpath =
- grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_PHYS_PATH);
- print_tabs (tab);
- if (!bootpath)
- grub_puts_ (N_("Bootpath: unavailable\n"));
- else
- grub_printf_ (N_("Bootpath: %s\n"), bootpath);
- path = grub_zfs_nvlist_lookup_string (nvlist, "path");
- print_tabs (tab);
- if (!path)
- grub_puts_ (N_("Path: unavailable"));
- else
- grub_printf_ (N_("Path: %s\n"), path);
- devid = grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_DEVID);
- print_tabs (tab);
- if (!devid)
- grub_puts_ (N_("Devid: unavailable"));
- else
- grub_printf_ (N_("Devid: %s\n"), devid);
- grub_free (bootpath);
- grub_free (devid);
- grub_free (path);
- grub_free (type);
- return GRUB_ERR_NONE;
- }
- char is_mirror=(grub_strcmp(type,VDEV_TYPE_MIRROR) == 0);
- char is_raidz=(grub_strcmp(type,VDEV_TYPE_RAIDZ) == 0);
- grub_free (type);
- if (is_mirror || is_raidz)
- {
- int nelm, i;
- nelm = grub_zfs_nvlist_lookup_nvlist_array_get_nelm
- (nvlist, ZPOOL_CONFIG_CHILDREN);
- if(is_mirror){
- grub_puts_ (N_("This VDEV is a mirror"));
- }
- else if(is_raidz){
- grub_uint64_t parity;
- grub_zfs_nvlist_lookup_uint64(nvlist,"nparity",&parity);
- grub_printf_ (N_("This VDEV is a RAIDZ%llu\n"),(unsigned long long)parity);
- }
- print_tabs (tab);
- if (nelm <= 0)
- {
- grub_puts_ (N_("Incorrect VDEV"));
- return GRUB_ERR_NONE;
- }
- grub_printf_ (N_("VDEV with %d children\n"), nelm);
- print_state (nvlist, tab);
- for (i = 0; i < nelm; i++)
- {
- char *child;
- child = grub_zfs_nvlist_lookup_nvlist_array
- (nvlist, ZPOOL_CONFIG_CHILDREN, i);
- print_tabs (tab);
- if (!child)
- {
- /* TRANSLATORS: it's the element carying the number %d, not
- total element number. And the number itself is fine,
- only the element isn't.
- */
- grub_printf_ (N_("VDEV element number %d isn't correct\n"), i);
- continue;
- }
- /* TRANSLATORS: it's the element carying the number %d, not
- total element number. This is used in enumeration
- "Element number 1", "Element number 2", ... */
- grub_printf_ (N_("VDEV element number %d:\n"), i);
- print_vdev_info (child, tab + 1);
- grub_free (child);
- }
- return GRUB_ERR_NONE;
- }
- print_tabs (tab);
- grub_printf_ (N_("Unknown virtual device type: %s\n"), type);
- return GRUB_ERR_NONE;
- }
- static grub_err_t
- get_bootpath (char *nvlist, char **bootpath, char **devid)
- {
- char *type = 0;
- type = grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_TYPE);
- if (!type)
- return grub_errno;
- if (grub_strcmp (type, VDEV_TYPE_DISK) == 0)
- {
- *bootpath = grub_zfs_nvlist_lookup_string (nvlist,
- ZPOOL_CONFIG_PHYS_PATH);
- *devid = grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_DEVID);
- if (!*bootpath || !*devid)
- {
- grub_free (*bootpath);
- grub_free (*devid);
- *bootpath = 0;
- *devid = 0;
- }
- return GRUB_ERR_NONE;
- }
- if (grub_strcmp (type, VDEV_TYPE_MIRROR) == 0)
- {
- int nelm, i;
- nelm = grub_zfs_nvlist_lookup_nvlist_array_get_nelm
- (nvlist, ZPOOL_CONFIG_CHILDREN);
- for (i = 0; i < nelm; i++)
- {
- char *child;
- child = grub_zfs_nvlist_lookup_nvlist_array (nvlist,
- ZPOOL_CONFIG_CHILDREN,
- i);
- get_bootpath (child, bootpath, devid);
- grub_free (child);
- if (*bootpath && *devid)
- return GRUB_ERR_NONE;
- }
- }
- return GRUB_ERR_NONE;
- }
- static const char *poolstates[] = {
- /* TRANSLATORS: Here we speak about ZFS pools it's semi-marketing,
- semi-technical term by Sun/Oracle and should be translated in sync with
- other ZFS-related software and documentation. */
- [POOL_STATE_ACTIVE] = N_("Pool state: active"),
- [POOL_STATE_EXPORTED] = N_("Pool state: exported"),
- [POOL_STATE_DESTROYED] = N_("Pool state: destroyed"),
- [POOL_STATE_SPARE] = N_("Pool state: reserved for hot spare"),
- [POOL_STATE_L2CACHE] = N_("Pool state: level 2 ARC device"),
- [POOL_STATE_UNINITIALIZED] = N_("Pool state: uninitialized"),
- [POOL_STATE_UNAVAIL] = N_("Pool state: unavailable"),
- [POOL_STATE_POTENTIALLY_ACTIVE] = N_("Pool state: potentially active")
- };
- static grub_err_t
- grub_cmd_zfsinfo (grub_command_t cmd __attribute__ ((unused)), int argc,
- char **args)
- {
- grub_device_t dev;
- char *devname;
- grub_err_t err;
- char *nvlist = 0;
- char *nv = 0;
- char *poolname;
- grub_uint64_t guid;
- grub_uint64_t pool_state;
- int found;
- if (argc < 1)
- return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
- if (args[0][0] == '(' && args[0][grub_strlen (args[0]) - 1] == ')')
- {
- devname = grub_strdup (args[0] + 1);
- if (devname)
- devname[grub_strlen (devname) - 1] = 0;
- }
- else
- devname = grub_strdup (args[0]);
- if (!devname)
- return grub_errno;
- dev = grub_device_open (devname);
- grub_free (devname);
- if (!dev)
- return grub_errno;
- err = grub_zfs_fetch_nvlist (dev, &nvlist);
- grub_device_close (dev);
- if (err)
- return err;
- poolname = grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_POOL_NAME);
- if (!poolname)
- grub_puts_ (N_("Pool name: unavailable"));
- else
- grub_printf_ (N_("Pool name: %s\n"), poolname);
- found =
- grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_POOL_GUID, &guid);
- if (!found)
- grub_puts_ (N_("Pool GUID: unavailable"));
- else
- grub_printf_ (N_("Pool GUID: %016llx\n"), (long long unsigned) guid);
- found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_POOL_STATE,
- &pool_state);
- if (!found)
- grub_puts_ (N_("Unable to retrieve pool state"));
- else if (pool_state >= ARRAY_SIZE (poolstates))
- grub_puts_ (N_("Unrecognized pool state"));
- else
- grub_puts_ (poolstates[pool_state]);
- nv = grub_zfs_nvlist_lookup_nvlist (nvlist, ZPOOL_CONFIG_VDEV_TREE);
- if (!nv)
- /* TRANSLATORS: There are undetermined number of virtual devices
- in a device tree, not just one.
- */
- grub_puts_ (N_("No virtual device tree available"));
- else
- print_vdev_info (nv, 1);
- grub_free (nv);
- grub_free (nvlist);
- return GRUB_ERR_NONE;
- }
- static grub_err_t
- grub_cmd_zfs_bootfs (grub_command_t cmd __attribute__ ((unused)), int argc,
- char **args)
- {
- grub_device_t dev;
- char *devname;
- grub_err_t err;
- char *nvlist = 0;
- char *nv = 0;
- char *bootpath = 0, *devid = 0;
- char *fsname;
- char *bootfs;
- char *poolname;
- grub_uint64_t mdnobj;
- if (argc < 1)
- return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
- devname = grub_file_get_device_name (args[0]);
- if (grub_errno)
- return grub_errno;
- dev = grub_device_open (devname);
- grub_free (devname);
- if (!dev)
- return grub_errno;
- err = grub_zfs_fetch_nvlist (dev, &nvlist);
- fsname = grub_strchr (args[0], ')');
- if (fsname)
- fsname++;
- else
- fsname = args[0];
- if (!err)
- err = grub_zfs_getmdnobj (dev, fsname, &mdnobj);
- grub_device_close (dev);
- if (err)
- return err;
- poolname = grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_POOL_NAME);
- if (!poolname)
- {
- if (!grub_errno)
- grub_error (GRUB_ERR_BAD_FS, "No poolname found");
- return grub_errno;
- }
- nv = grub_zfs_nvlist_lookup_nvlist (nvlist, ZPOOL_CONFIG_VDEV_TREE);
- if (nv)
- get_bootpath (nv, &bootpath, &devid);
- grub_free (nv);
- grub_free (nvlist);
- bootfs = grub_xasprintf ("zfs-bootfs=%s/%llu%s%s%s%s%s%s",
- poolname, (unsigned long long) mdnobj,
- bootpath ? ",bootpath=\"" : "",
- bootpath ? : "",
- bootpath ? "\"" : "",
- devid ? ",diskdevid=\"" : "",
- devid ? : "",
- devid ? "\"" : "");
- if (!bootfs)
- return grub_errno;
- if (argc >= 2)
- grub_env_set (args[1], bootfs);
- else
- grub_printf ("%s\n", bootfs);
- grub_free (bootfs);
- grub_free (poolname);
- grub_free (bootpath);
- grub_free (devid);
- return GRUB_ERR_NONE;
- }
- static grub_command_t cmd_info, cmd_bootfs;
- GRUB_MOD_INIT (zfsinfo)
- {
- cmd_info = grub_register_command ("zfsinfo", grub_cmd_zfsinfo,
- N_("DEVICE"),
- N_("Print ZFS info about DEVICE."));
- cmd_bootfs = grub_register_command ("zfs-bootfs", grub_cmd_zfs_bootfs,
- N_("FILESYSTEM [VARIABLE]"),
- N_("Print ZFS-BOOTFSOBJ or store it into VARIABLE"));
- }
- GRUB_MOD_FINI (zfsinfo)
- {
- grub_unregister_command (cmd_info);
- grub_unregister_command (cmd_bootfs);
- }
|