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