]> git.proxmox.com Git - grub2.git/blob - grub-core/fs/zfs/zfsinfo.c
* grub-core/fs/fat.c: Include grub/fat.h.
[grub2.git] / grub-core / fs / zfs / zfsinfo.c
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
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>
28
29 GRUB_MOD_LICENSE ("GPLv3+");
30
31 static inline void
32 print_tabs (int n)
33 {
34 int i;
35
36 for (i = 0; i < n; i++)
37 grub_printf (" ");
38 }
39
40 static grub_err_t
41 print_state (char *nvlist, int tab)
42 {
43 grub_uint64_t ival;
44 int isok = 1;
45
46 print_tabs (tab);
47 grub_printf ("State: ");
48
49 if (grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_REMOVED, &ival))
50 {
51 grub_printf ("removed ");
52 isok = 0;
53 }
54
55 if (grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_FAULTED, &ival))
56 {
57 grub_printf ("faulted ");
58 isok = 0;
59 }
60
61 if (grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_OFFLINE, &ival))
62 {
63 grub_printf ("offline ");
64 isok = 0;
65 }
66
67 if (grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_FAULTED, &ival))
68 grub_printf ("degraded ");
69
70 if (isok)
71 grub_printf ("online");
72 grub_printf ("\n");
73
74 return GRUB_ERR_NONE;
75 }
76
77 static grub_err_t
78 print_vdev_info (char *nvlist, int tab)
79 {
80 char *type = 0;
81
82 type = grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_TYPE);
83
84 if (!type)
85 {
86 print_tabs (tab);
87 grub_printf ("Incorrect VDEV: no type available\n");
88 return grub_errno;
89 }
90
91 if (grub_strcmp (type, VDEV_TYPE_DISK) == 0)
92 {
93 char *bootpath = 0;
94 char *path = 0;
95 char *devid = 0;
96
97 print_tabs (tab);
98 grub_printf ("Leaf VDEV\n");
99
100 print_state (nvlist, tab);
101
102 bootpath =
103 grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_PHYS_PATH);
104 print_tabs (tab);
105 if (!bootpath)
106 grub_printf ("Bootpath: unavailable\n");
107 else
108 grub_printf ("Bootpath: %s\n", bootpath);
109
110 path = grub_zfs_nvlist_lookup_string (nvlist, "path");
111 print_tabs (tab);
112 if (!path)
113 grub_printf ("Path: unavailable\n");
114 else
115 grub_printf ("Path: %s\n", path);
116
117 devid = grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_DEVID);
118 print_tabs (tab);
119 if (!devid)
120 grub_printf ("Devid: unavailable\n");
121 else
122 grub_printf ("Devid: %s\n", devid);
123 grub_free (bootpath);
124 grub_free (devid);
125 grub_free (path);
126 return GRUB_ERR_NONE;
127 }
128
129 if (grub_strcmp (type, VDEV_TYPE_MIRROR) == 0)
130 {
131 int nelm, i;
132
133 nelm = grub_zfs_nvlist_lookup_nvlist_array_get_nelm
134 (nvlist, ZPOOL_CONFIG_CHILDREN);
135
136 print_tabs (tab);
137 if (nelm <= 0)
138 {
139 grub_printf ("Incorrect mirror VDEV\n");
140 return GRUB_ERR_NONE;
141 }
142 grub_printf ("Mirror VDEV with %d children\n", nelm);
143 print_state (nvlist, tab);
144
145 for (i = 0; i < nelm; i++)
146 {
147 char *child;
148
149 child = grub_zfs_nvlist_lookup_nvlist_array
150 (nvlist, ZPOOL_CONFIG_CHILDREN, i);
151
152 print_tabs (tab);
153 if (!child)
154 {
155 grub_printf ("Mirror VDEV element %d isn't correct\n", i);
156 continue;
157 }
158
159 grub_printf ("Mirror VDEV element %d:\n", i);
160 print_vdev_info (child, tab + 1);
161
162 grub_free (child);
163 }
164 }
165
166 print_tabs (tab);
167 grub_printf ("Unknown VDEV type: %s\n", type);
168
169 return GRUB_ERR_NONE;
170 }
171
172 static grub_err_t
173 get_bootpath (char *nvlist, char **bootpath, char **devid)
174 {
175 char *type = 0;
176
177 type = grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_TYPE);
178
179 if (!type)
180 return grub_errno;
181
182 if (grub_strcmp (type, VDEV_TYPE_DISK) == 0)
183 {
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)
188 {
189 grub_free (*bootpath);
190 grub_free (*devid);
191 *bootpath = 0;
192 *devid = 0;
193 }
194 return GRUB_ERR_NONE;
195 }
196
197 if (grub_strcmp (type, VDEV_TYPE_MIRROR) == 0)
198 {
199 int nelm, i;
200
201 nelm = grub_zfs_nvlist_lookup_nvlist_array_get_nelm
202 (nvlist, ZPOOL_CONFIG_CHILDREN);
203
204 for (i = 0; i < nelm; i++)
205 {
206 char *child;
207
208 child = grub_zfs_nvlist_lookup_nvlist_array (nvlist,
209 ZPOOL_CONFIG_CHILDREN,
210 i);
211
212 get_bootpath (child, bootpath, devid);
213
214 grub_free (child);
215
216 if (*bootpath && *devid)
217 return GRUB_ERR_NONE;
218 }
219 }
220
221 return GRUB_ERR_NONE;
222 }
223
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"
233 };
234
235 static grub_err_t
236 grub_cmd_zfsinfo (grub_command_t cmd __attribute__ ((unused)), int argc,
237 char **args)
238 {
239 grub_device_t dev;
240 char *devname;
241 grub_err_t err;
242 char *nvlist = 0;
243 char *nv = 0;
244 char *poolname;
245 grub_uint64_t guid;
246 grub_uint64_t pool_state;
247 int found;
248
249 if (argc < 1)
250 return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required");
251
252 if (args[0][0] == '(' && args[0][grub_strlen (args[0]) - 1] == ')')
253 {
254 devname = grub_strdup (args[0] + 1);
255 if (devname)
256 devname[grub_strlen (devname) - 1] = 0;
257 }
258 else
259 devname = grub_strdup (args[0]);
260 if (!devname)
261 return grub_errno;
262
263 dev = grub_device_open (devname);
264 grub_free (devname);
265 if (!dev)
266 return grub_errno;
267
268 err = grub_zfs_fetch_nvlist (dev, &nvlist);
269
270 grub_device_close (dev);
271
272 if (err)
273 return err;
274
275 poolname = grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_POOL_NAME);
276 if (!poolname)
277 grub_printf ("Pool name: unavailable\n");
278 else
279 grub_printf ("Pool name: %s\n", poolname);
280
281 found =
282 grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_POOL_GUID, &guid);
283 if (!found)
284 grub_printf ("Pool GUID: unavailable\n");
285 else
286 grub_printf ("Pool GUID: %016llx\n", (long long unsigned) guid);
287
288 found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_POOL_STATE,
289 &pool_state);
290 if (!found)
291 grub_printf ("Unable to retrieve pool state\n");
292 else if (pool_state >= ARRAY_SIZE (poolstates))
293 grub_printf ("Unrecognized pool state\n");
294 else
295 grub_printf ("Pool state: %s\n", poolstates[pool_state]);
296
297 nv = grub_zfs_nvlist_lookup_nvlist (nvlist, ZPOOL_CONFIG_VDEV_TREE);
298
299 if (!nv)
300 grub_printf ("No vdev tree available\n");
301 else
302 print_vdev_info (nv, 1);
303
304 grub_free (nv);
305 grub_free (nvlist);
306
307 return GRUB_ERR_NONE;
308 }
309
310 static grub_err_t
311 grub_cmd_zfs_bootfs (grub_command_t cmd __attribute__ ((unused)), int argc,
312 char **args)
313 {
314 grub_device_t dev;
315 char *devname;
316 grub_err_t err;
317 char *nvlist = 0;
318 char *nv = 0;
319 char *bootpath = 0, *devid = 0;
320 char *fsname;
321 char *bootfs;
322 char *poolname;
323 grub_uint64_t mdnobj;
324
325 if (argc < 1)
326 return grub_error (GRUB_ERR_BAD_ARGUMENT, "filesystem name required");
327
328 devname = grub_file_get_device_name (args[0]);
329 if (grub_errno)
330 return grub_errno;
331
332 dev = grub_device_open (devname);
333 grub_free (devname);
334 if (!dev)
335 return grub_errno;
336
337 err = grub_zfs_fetch_nvlist (dev, &nvlist);
338
339 fsname = grub_strchr (args[0], ')');
340 if (fsname)
341 fsname++;
342 else
343 fsname = args[0];
344
345 if (!err)
346 err = grub_zfs_getmdnobj (dev, fsname, &mdnobj);
347
348 grub_device_close (dev);
349
350 if (err)
351 return err;
352
353 poolname = grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_POOL_NAME);
354 if (!poolname)
355 {
356 if (!grub_errno)
357 grub_error (GRUB_ERR_BAD_FS, "No poolname found");
358 return grub_errno;
359 }
360
361 nv = grub_zfs_nvlist_lookup_nvlist (nvlist, ZPOOL_CONFIG_VDEV_TREE);
362
363 if (nv)
364 get_bootpath (nv, &bootpath, &devid);
365
366 grub_free (nv);
367 grub_free (nvlist);
368
369 bootfs = grub_xasprintf ("zfs-bootfs=%s/%llu%s%s%s%s%s%s",
370 poolname, (unsigned long long) mdnobj,
371 bootpath ? ",bootpath=\"" : "",
372 bootpath ? : "",
373 bootpath ? "\"" : "",
374 devid ? ",diskdevid=\"" : "",
375 devid ? : "",
376 devid ? "\"" : "");
377 if (!bootfs)
378 return grub_errno;
379 if (argc >= 2)
380 grub_env_set (args[1], bootfs);
381 else
382 grub_printf ("%s\n", bootfs);
383
384 grub_free (bootfs);
385 grub_free (poolname);
386 grub_free (bootpath);
387 grub_free (devid);
388
389 return GRUB_ERR_NONE;
390 }
391
392
393 static grub_command_t cmd_info, cmd_bootfs;
394
395 GRUB_MOD_INIT (zfsinfo)
396 {
397 cmd_info = grub_register_command ("zfsinfo", grub_cmd_zfsinfo,
398 "zfsinfo DEVICE",
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");
403 }
404
405 GRUB_MOD_FINI (zfsinfo)
406 {
407 grub_unregister_command (cmd_info);
408 grub_unregister_command (cmd_bootfs);
409 }