zfsinfo.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  1. /*
  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.
  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. #include <grub/zfs/zfs.h>
  20. #include <grub/device.h>
  21. #include <grub/file.h>
  22. #include <grub/command.h>
  23. #include <grub/misc.h>
  24. #include <grub/mm.h>
  25. #include <grub/dl.h>
  26. #include <grub/env.h>
  27. #include <grub/i18n.h>
  28. GRUB_MOD_LICENSE ("GPLv3+");
  29. static inline void
  30. print_tabs (int n)
  31. {
  32. int i;
  33. for (i = 0; i < n; i++)
  34. grub_printf (" ");
  35. }
  36. static grub_err_t
  37. print_state (char *nvlist, int tab)
  38. {
  39. grub_uint64_t ival;
  40. int isok = 1;
  41. print_tabs (tab);
  42. if (grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_REMOVED, &ival))
  43. {
  44. grub_puts_ (N_("Virtual device is removed"));
  45. isok = 0;
  46. }
  47. if (grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_FAULTED, &ival))
  48. {
  49. grub_puts_ (N_("Virtual device is faulted"));
  50. isok = 0;
  51. }
  52. if (grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_OFFLINE, &ival))
  53. {
  54. grub_puts_ (N_("Virtual device is offline"));
  55. isok = 0;
  56. }
  57. if (grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_FAULTED, &ival))
  58. /* TRANSLATORS: degraded doesn't mean broken but that some of
  59. component are missing but virtual device as whole is still usable. */
  60. grub_puts_ (N_("Virtual device is degraded"));
  61. if (isok)
  62. grub_puts_ (N_("Virtual device is online"));
  63. grub_xputs ("\n");
  64. return GRUB_ERR_NONE;
  65. }
  66. static grub_err_t
  67. print_vdev_info (char *nvlist, int tab)
  68. {
  69. char *type = 0;
  70. type = grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_TYPE);
  71. if (!type)
  72. {
  73. print_tabs (tab);
  74. grub_puts_ (N_("Incorrect virtual device: no type available"));
  75. return grub_errno;
  76. }
  77. if (grub_strcmp (type, VDEV_TYPE_DISK) == 0)
  78. {
  79. char *bootpath = 0;
  80. char *path = 0;
  81. char *devid = 0;
  82. print_tabs (tab);
  83. /* TRANSLATORS: The virtual devices form a tree (in graph-theoretical
  84. sense). The nodes like mirror or raidz have children: member devices.
  85. The "real" devices which actually store data are called "leafs"
  86. (again borrowed from graph theory) and can be either disks
  87. (or partitions) or files. */
  88. grub_puts_ (N_("Leaf virtual device (file or disk)"));
  89. print_state (nvlist, tab);
  90. bootpath =
  91. grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_PHYS_PATH);
  92. print_tabs (tab);
  93. if (!bootpath)
  94. grub_puts_ (N_("Bootpath: unavailable\n"));
  95. else
  96. grub_printf_ (N_("Bootpath: %s\n"), bootpath);
  97. path = grub_zfs_nvlist_lookup_string (nvlist, "path");
  98. print_tabs (tab);
  99. if (!path)
  100. grub_puts_ (N_("Path: unavailable"));
  101. else
  102. grub_printf_ (N_("Path: %s\n"), path);
  103. devid = grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_DEVID);
  104. print_tabs (tab);
  105. if (!devid)
  106. grub_puts_ (N_("Devid: unavailable"));
  107. else
  108. grub_printf_ (N_("Devid: %s\n"), devid);
  109. grub_free (bootpath);
  110. grub_free (devid);
  111. grub_free (path);
  112. grub_free (type);
  113. return GRUB_ERR_NONE;
  114. }
  115. char is_mirror=(grub_strcmp(type,VDEV_TYPE_MIRROR) == 0);
  116. char is_raidz=(grub_strcmp(type,VDEV_TYPE_RAIDZ) == 0);
  117. grub_free (type);
  118. if (is_mirror || is_raidz)
  119. {
  120. int nelm, i;
  121. nelm = grub_zfs_nvlist_lookup_nvlist_array_get_nelm
  122. (nvlist, ZPOOL_CONFIG_CHILDREN);
  123. if(is_mirror){
  124. grub_puts_ (N_("This VDEV is a mirror"));
  125. }
  126. else if(is_raidz){
  127. grub_uint64_t parity;
  128. grub_zfs_nvlist_lookup_uint64(nvlist,"nparity",&parity);
  129. grub_printf_ (N_("This VDEV is a RAIDZ%llu\n"),(unsigned long long)parity);
  130. }
  131. print_tabs (tab);
  132. if (nelm <= 0)
  133. {
  134. grub_puts_ (N_("Incorrect VDEV"));
  135. return GRUB_ERR_NONE;
  136. }
  137. grub_printf_ (N_("VDEV with %d children\n"), nelm);
  138. print_state (nvlist, tab);
  139. for (i = 0; i < nelm; i++)
  140. {
  141. char *child;
  142. child = grub_zfs_nvlist_lookup_nvlist_array
  143. (nvlist, ZPOOL_CONFIG_CHILDREN, i);
  144. print_tabs (tab);
  145. if (!child)
  146. {
  147. /* TRANSLATORS: it's the element carying the number %d, not
  148. total element number. And the number itself is fine,
  149. only the element isn't.
  150. */
  151. grub_printf_ (N_("VDEV element number %d isn't correct\n"), i);
  152. continue;
  153. }
  154. /* TRANSLATORS: it's the element carying the number %d, not
  155. total element number. This is used in enumeration
  156. "Element number 1", "Element number 2", ... */
  157. grub_printf_ (N_("VDEV element number %d:\n"), i);
  158. print_vdev_info (child, tab + 1);
  159. grub_free (child);
  160. }
  161. return GRUB_ERR_NONE;
  162. }
  163. print_tabs (tab);
  164. grub_printf_ (N_("Unknown virtual device type: %s\n"), type);
  165. return GRUB_ERR_NONE;
  166. }
  167. static grub_err_t
  168. get_bootpath (char *nvlist, char **bootpath, char **devid)
  169. {
  170. char *type = 0;
  171. type = grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_TYPE);
  172. if (!type)
  173. return grub_errno;
  174. if (grub_strcmp (type, VDEV_TYPE_DISK) == 0)
  175. {
  176. *bootpath = grub_zfs_nvlist_lookup_string (nvlist,
  177. ZPOOL_CONFIG_PHYS_PATH);
  178. *devid = grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_DEVID);
  179. if (!*bootpath || !*devid)
  180. {
  181. grub_free (*bootpath);
  182. grub_free (*devid);
  183. *bootpath = 0;
  184. *devid = 0;
  185. }
  186. return GRUB_ERR_NONE;
  187. }
  188. if (grub_strcmp (type, VDEV_TYPE_MIRROR) == 0)
  189. {
  190. int nelm, i;
  191. nelm = grub_zfs_nvlist_lookup_nvlist_array_get_nelm
  192. (nvlist, ZPOOL_CONFIG_CHILDREN);
  193. for (i = 0; i < nelm; i++)
  194. {
  195. char *child;
  196. child = grub_zfs_nvlist_lookup_nvlist_array (nvlist,
  197. ZPOOL_CONFIG_CHILDREN,
  198. i);
  199. get_bootpath (child, bootpath, devid);
  200. grub_free (child);
  201. if (*bootpath && *devid)
  202. return GRUB_ERR_NONE;
  203. }
  204. }
  205. return GRUB_ERR_NONE;
  206. }
  207. static const char *poolstates[] = {
  208. /* TRANSLATORS: Here we speak about ZFS pools it's semi-marketing,
  209. semi-technical term by Sun/Oracle and should be translated in sync with
  210. other ZFS-related software and documentation. */
  211. [POOL_STATE_ACTIVE] = N_("Pool state: active"),
  212. [POOL_STATE_EXPORTED] = N_("Pool state: exported"),
  213. [POOL_STATE_DESTROYED] = N_("Pool state: destroyed"),
  214. [POOL_STATE_SPARE] = N_("Pool state: reserved for hot spare"),
  215. [POOL_STATE_L2CACHE] = N_("Pool state: level 2 ARC device"),
  216. [POOL_STATE_UNINITIALIZED] = N_("Pool state: uninitialized"),
  217. [POOL_STATE_UNAVAIL] = N_("Pool state: unavailable"),
  218. [POOL_STATE_POTENTIALLY_ACTIVE] = N_("Pool state: potentially active")
  219. };
  220. static grub_err_t
  221. grub_cmd_zfsinfo (grub_command_t cmd __attribute__ ((unused)), int argc,
  222. char **args)
  223. {
  224. grub_device_t dev;
  225. char *devname;
  226. grub_err_t err;
  227. char *nvlist = 0;
  228. char *nv = 0;
  229. char *poolname;
  230. grub_uint64_t guid;
  231. grub_uint64_t pool_state;
  232. int found;
  233. if (argc < 1)
  234. return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
  235. if (args[0][0] == '(' && args[0][grub_strlen (args[0]) - 1] == ')')
  236. {
  237. devname = grub_strdup (args[0] + 1);
  238. if (devname)
  239. devname[grub_strlen (devname) - 1] = 0;
  240. }
  241. else
  242. devname = grub_strdup (args[0]);
  243. if (!devname)
  244. return grub_errno;
  245. dev = grub_device_open (devname);
  246. grub_free (devname);
  247. if (!dev)
  248. return grub_errno;
  249. err = grub_zfs_fetch_nvlist (dev, &nvlist);
  250. grub_device_close (dev);
  251. if (err)
  252. return err;
  253. poolname = grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_POOL_NAME);
  254. if (!poolname)
  255. grub_puts_ (N_("Pool name: unavailable"));
  256. else
  257. grub_printf_ (N_("Pool name: %s\n"), poolname);
  258. found =
  259. grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_POOL_GUID, &guid);
  260. if (!found)
  261. grub_puts_ (N_("Pool GUID: unavailable"));
  262. else
  263. grub_printf_ (N_("Pool GUID: %016llx\n"), (long long unsigned) guid);
  264. found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_POOL_STATE,
  265. &pool_state);
  266. if (!found)
  267. grub_puts_ (N_("Unable to retrieve pool state"));
  268. else if (pool_state >= ARRAY_SIZE (poolstates))
  269. grub_puts_ (N_("Unrecognized pool state"));
  270. else
  271. grub_puts_ (poolstates[pool_state]);
  272. nv = grub_zfs_nvlist_lookup_nvlist (nvlist, ZPOOL_CONFIG_VDEV_TREE);
  273. if (!nv)
  274. /* TRANSLATORS: There are undetermined number of virtual devices
  275. in a device tree, not just one.
  276. */
  277. grub_puts_ (N_("No virtual device tree available"));
  278. else
  279. print_vdev_info (nv, 1);
  280. grub_free (nv);
  281. grub_free (nvlist);
  282. return GRUB_ERR_NONE;
  283. }
  284. static grub_err_t
  285. grub_cmd_zfs_bootfs (grub_command_t cmd __attribute__ ((unused)), int argc,
  286. char **args)
  287. {
  288. grub_device_t dev;
  289. char *devname;
  290. grub_err_t err;
  291. char *nvlist = 0;
  292. char *nv = 0;
  293. char *bootpath = 0, *devid = 0;
  294. char *fsname;
  295. char *bootfs;
  296. char *poolname;
  297. grub_uint64_t mdnobj;
  298. if (argc < 1)
  299. return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
  300. devname = grub_file_get_device_name (args[0]);
  301. if (grub_errno)
  302. return grub_errno;
  303. dev = grub_device_open (devname);
  304. grub_free (devname);
  305. if (!dev)
  306. return grub_errno;
  307. err = grub_zfs_fetch_nvlist (dev, &nvlist);
  308. fsname = grub_strchr (args[0], ')');
  309. if (fsname)
  310. fsname++;
  311. else
  312. fsname = args[0];
  313. if (!err)
  314. err = grub_zfs_getmdnobj (dev, fsname, &mdnobj);
  315. grub_device_close (dev);
  316. if (err)
  317. return err;
  318. poolname = grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_POOL_NAME);
  319. if (!poolname)
  320. {
  321. if (!grub_errno)
  322. grub_error (GRUB_ERR_BAD_FS, "No poolname found");
  323. return grub_errno;
  324. }
  325. nv = grub_zfs_nvlist_lookup_nvlist (nvlist, ZPOOL_CONFIG_VDEV_TREE);
  326. if (nv)
  327. get_bootpath (nv, &bootpath, &devid);
  328. grub_free (nv);
  329. grub_free (nvlist);
  330. bootfs = grub_xasprintf ("zfs-bootfs=%s/%llu%s%s%s%s%s%s",
  331. poolname, (unsigned long long) mdnobj,
  332. bootpath ? ",bootpath=\"" : "",
  333. bootpath ? : "",
  334. bootpath ? "\"" : "",
  335. devid ? ",diskdevid=\"" : "",
  336. devid ? : "",
  337. devid ? "\"" : "");
  338. if (!bootfs)
  339. return grub_errno;
  340. if (argc >= 2)
  341. grub_env_set (args[1], bootfs);
  342. else
  343. grub_printf ("%s\n", bootfs);
  344. grub_free (bootfs);
  345. grub_free (poolname);
  346. grub_free (bootpath);
  347. grub_free (devid);
  348. return GRUB_ERR_NONE;
  349. }
  350. static grub_command_t cmd_info, cmd_bootfs;
  351. GRUB_MOD_INIT (zfsinfo)
  352. {
  353. cmd_info = grub_register_command ("zfsinfo", grub_cmd_zfsinfo,
  354. N_("DEVICE"),
  355. N_("Print ZFS info about DEVICE."));
  356. cmd_bootfs = grub_register_command ("zfs-bootfs", grub_cmd_zfs_bootfs,
  357. N_("FILESYSTEM [VARIABLE]"),
  358. N_("Print ZFS-BOOTFSOBJ or store it into VARIABLE"));
  359. }
  360. GRUB_MOD_FINI (zfsinfo)
  361. {
  362. grub_unregister_command (cmd_info);
  363. grub_unregister_command (cmd_bootfs);
  364. }