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