]> git.proxmox.com Git - grub2.git/blob - grub-core/fs/zfs/zfsinfo.c
ZFS crypto key adding
[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/extcmd.h>
25 #include <grub/misc.h>
26 #include <grub/mm.h>
27 #include <grub/dl.h>
28 #include <grub/env.h>
29 #include <grub/i18n.h>
30
31 GRUB_MOD_LICENSE ("GPLv3+");
32
33 static inline void
34 print_tabs (int n)
35 {
36 int i;
37
38 for (i = 0; i < n; i++)
39 grub_printf (" ");
40 }
41
42 static grub_err_t
43 print_state (char *nvlist, int tab)
44 {
45 grub_uint64_t ival;
46 int isok = 1;
47
48 print_tabs (tab);
49 grub_printf ("State: ");
50
51 if (grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_REMOVED, &ival))
52 {
53 grub_printf ("removed ");
54 isok = 0;
55 }
56
57 if (grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_FAULTED, &ival))
58 {
59 grub_printf ("faulted ");
60 isok = 0;
61 }
62
63 if (grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_OFFLINE, &ival))
64 {
65 grub_printf ("offline ");
66 isok = 0;
67 }
68
69 if (grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_FAULTED, &ival))
70 grub_printf ("degraded ");
71
72 if (isok)
73 grub_printf ("online");
74 grub_printf ("\n");
75
76 return GRUB_ERR_NONE;
77 }
78
79 static grub_err_t
80 print_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);
89 grub_printf ("Incorrect VDEV: no type available\n");
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);
100 grub_printf ("Leaf VDEV\n");
101
102 print_state (nvlist, tab);
103
104 bootpath =
105 grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_PHYS_PATH);
106 print_tabs (tab);
107 if (!bootpath)
108 grub_printf ("Bootpath: unavailable\n");
109 else
110 grub_printf ("Bootpath: %s\n", bootpath);
111
112 path = grub_zfs_nvlist_lookup_string (nvlist, "path");
113 print_tabs (tab);
114 if (!path)
115 grub_printf ("Path: unavailable\n");
116 else
117 grub_printf ("Path: %s\n", path);
118
119 devid = grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_DEVID);
120 print_tabs (tab);
121 if (!devid)
122 grub_printf ("Devid: unavailable\n");
123 else
124 grub_printf ("Devid: %s\n", devid);
125 grub_free (bootpath);
126 grub_free (devid);
127 grub_free (path);
128 return GRUB_ERR_NONE;
129 }
130
131 if (grub_strcmp (type, VDEV_TYPE_MIRROR) == 0)
132 {
133 int nelm, i;
134
135 nelm = grub_zfs_nvlist_lookup_nvlist_array_get_nelm
136 (nvlist, ZPOOL_CONFIG_CHILDREN);
137
138 print_tabs (tab);
139 if (nelm <= 0)
140 {
141 grub_printf ("Incorrect mirror VDEV\n");
142 return GRUB_ERR_NONE;
143 }
144 grub_printf ("Mirror VDEV with %d children\n", nelm);
145 print_state (nvlist, tab);
146 for (i = 0; i < nelm; i++)
147 {
148 char *child;
149
150 child = grub_zfs_nvlist_lookup_nvlist_array
151 (nvlist, ZPOOL_CONFIG_CHILDREN, i);
152
153 print_tabs (tab);
154 if (!child)
155 {
156 grub_printf ("Mirror VDEV element %d isn't correct\n", i);
157 continue;
158 }
159
160 grub_printf ("Mirror VDEV element %d:\n", i);
161 print_vdev_info (child, tab + 1);
162
163 grub_free (child);
164 }
165 return GRUB_ERR_NONE;
166 }
167
168 print_tabs (tab);
169 grub_printf ("Unknown VDEV type: %s\n", type);
170
171 return GRUB_ERR_NONE;
172 }
173
174 static grub_err_t
175 get_bootpath (char *nvlist, char **bootpath, char **devid)
176 {
177 char *type = 0;
178
179 type = grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_TYPE);
180
181 if (!type)
182 return grub_errno;
183
184 if (grub_strcmp (type, VDEV_TYPE_DISK) == 0)
185 {
186 *bootpath = grub_zfs_nvlist_lookup_string (nvlist,
187 ZPOOL_CONFIG_PHYS_PATH);
188 *devid = grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_DEVID);
189 if (!*bootpath || !*devid)
190 {
191 grub_free (*bootpath);
192 grub_free (*devid);
193 *bootpath = 0;
194 *devid = 0;
195 }
196 return GRUB_ERR_NONE;
197 }
198
199 if (grub_strcmp (type, VDEV_TYPE_MIRROR) == 0)
200 {
201 int nelm, i;
202
203 nelm = grub_zfs_nvlist_lookup_nvlist_array_get_nelm
204 (nvlist, ZPOOL_CONFIG_CHILDREN);
205
206 for (i = 0; i < nelm; i++)
207 {
208 char *child;
209
210 child = grub_zfs_nvlist_lookup_nvlist_array (nvlist,
211 ZPOOL_CONFIG_CHILDREN,
212 i);
213
214 get_bootpath (child, bootpath, devid);
215
216 grub_free (child);
217
218 if (*bootpath && *devid)
219 return GRUB_ERR_NONE;
220 }
221 }
222
223 return GRUB_ERR_NONE;
224 }
225
226 static char *poolstates[] = {
227 [POOL_STATE_ACTIVE] = "active",
228 [POOL_STATE_EXPORTED] = "exported",
229 [POOL_STATE_DESTROYED] = "destroyed",
230 [POOL_STATE_SPARE] = "reserved for hot spare",
231 [POOL_STATE_L2CACHE] = "level 2 ARC device",
232 [POOL_STATE_UNINITIALIZED] = "uninitialized",
233 [POOL_STATE_UNAVAIL] = "unavailable",
234 [POOL_STATE_POTENTIALLY_ACTIVE] = "potentially active"
235 };
236
237 static grub_err_t
238 grub_cmd_zfsinfo (grub_command_t cmd __attribute__ ((unused)), int argc,
239 char **args)
240 {
241 grub_device_t dev;
242 char *devname;
243 grub_err_t err;
244 char *nvlist = 0;
245 char *nv = 0;
246 char *poolname;
247 grub_uint64_t guid;
248 grub_uint64_t pool_state;
249 int found;
250
251 if (argc < 1)
252 return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required");
253
254 if (args[0][0] == '(' && args[0][grub_strlen (args[0]) - 1] == ')')
255 {
256 devname = grub_strdup (args[0] + 1);
257 if (devname)
258 devname[grub_strlen (devname) - 1] = 0;
259 }
260 else
261 devname = grub_strdup (args[0]);
262 if (!devname)
263 return grub_errno;
264
265 dev = grub_device_open (devname);
266 grub_free (devname);
267 if (!dev)
268 return grub_errno;
269
270 err = grub_zfs_fetch_nvlist (dev, &nvlist);
271
272 grub_device_close (dev);
273
274 if (err)
275 return err;
276
277 poolname = grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_POOL_NAME);
278 if (!poolname)
279 grub_printf ("Pool name: unavailable\n");
280 else
281 grub_printf ("Pool name: %s\n", poolname);
282
283 found =
284 grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_POOL_GUID, &guid);
285 if (!found)
286 grub_printf ("Pool GUID: unavailable\n");
287 else
288 grub_printf ("Pool GUID: %016llx\n", (long long unsigned) guid);
289
290 found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_POOL_STATE,
291 &pool_state);
292 if (!found)
293 grub_printf ("Unable to retrieve pool state\n");
294 else if (pool_state >= ARRAY_SIZE (poolstates))
295 grub_printf ("Unrecognized pool state\n");
296 else
297 grub_printf ("Pool state: %s\n", poolstates[pool_state]);
298
299 nv = grub_zfs_nvlist_lookup_nvlist (nvlist, ZPOOL_CONFIG_VDEV_TREE);
300
301 if (!nv)
302 grub_printf ("No vdev tree available\n");
303 else
304 print_vdev_info (nv, 1);
305
306 grub_free (nv);
307 grub_free (nvlist);
308
309 return GRUB_ERR_NONE;
310 }
311
312 static grub_err_t
313 grub_cmd_zfs_bootfs (grub_command_t cmd __attribute__ ((unused)), int argc,
314 char **args)
315 {
316 grub_device_t dev;
317 char *devname;
318 grub_err_t err;
319 char *nvlist = 0;
320 char *nv = 0;
321 char *bootpath = 0, *devid = 0;
322 char *fsname;
323 char *bootfs;
324 char *poolname;
325 grub_uint64_t mdnobj;
326
327 if (argc < 1)
328 return grub_error (GRUB_ERR_BAD_ARGUMENT, "filesystem name required");
329
330 devname = grub_file_get_device_name (args[0]);
331 if (grub_errno)
332 return grub_errno;
333
334 dev = grub_device_open (devname);
335 grub_free (devname);
336 if (!dev)
337 return grub_errno;
338
339 err = grub_zfs_fetch_nvlist (dev, &nvlist);
340
341 fsname = grub_strchr (args[0], ')');
342 if (fsname)
343 fsname++;
344 else
345 fsname = args[0];
346
347 if (!err)
348 err = grub_zfs_getmdnobj (dev, fsname, &mdnobj);
349
350 grub_device_close (dev);
351
352 if (err)
353 return err;
354
355 poolname = grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_POOL_NAME);
356 if (!poolname)
357 {
358 if (!grub_errno)
359 grub_error (GRUB_ERR_BAD_FS, "No poolname found");
360 return grub_errno;
361 }
362
363 nv = grub_zfs_nvlist_lookup_nvlist (nvlist, ZPOOL_CONFIG_VDEV_TREE);
364
365 if (nv)
366 get_bootpath (nv, &bootpath, &devid);
367
368 grub_free (nv);
369 grub_free (nvlist);
370
371 bootfs = grub_xasprintf ("zfs-bootfs=%s/%llu%s%s%s%s%s%s",
372 poolname, (unsigned long long) mdnobj,
373 bootpath ? ",bootpath=\"" : "",
374 bootpath ? : "",
375 bootpath ? "\"" : "",
376 devid ? ",diskdevid=\"" : "",
377 devid ? : "",
378 devid ? "\"" : "");
379 if (!bootfs)
380 return grub_errno;
381 if (argc >= 2)
382 grub_env_set (args[1], bootfs);
383 else
384 grub_printf ("%s\n", bootfs);
385
386 grub_free (bootfs);
387 grub_free (poolname);
388 grub_free (bootpath);
389 grub_free (devid);
390
391 return GRUB_ERR_NONE;
392 }
393
394 static const struct grub_arg_option options[] =
395 {
396 {"raw", 'r', 0, N_("Assume input is raw."), 0, 0},
397 {"hex", 'h', 0, N_("Assume input is hex."), 0, 0},
398 {"passphrase", 'p', 0, N_("Assume input is passphrase."), 0, 0},
399 {0, 0, 0, 0, 0, 0}
400 };
401
402 static grub_err_t
403 grub_cmd_zfs_key (grub_extcmd_context_t ctxt, int argc, char **args)
404 {
405 grub_uint8_t buf[1024];
406 grub_ssize_t real_size;
407
408 if (argc > 0)
409 {
410 grub_file_t file;
411 file = grub_file_open (args[0]);
412 if (!file)
413 return grub_errno;
414 real_size = grub_file_read (file, buf, 1024);
415 if (real_size < 0)
416 return grub_errno;
417 }
418 if (ctxt->state[0].set
419 || (argc > 0 && !ctxt->state[1].set && !ctxt->state[2].set))
420 {
421 grub_err_t err;
422 if (real_size < GRUB_ZFS_MAX_KEYLEN)
423 grub_memset (buf + real_size, 0, GRUB_ZFS_MAX_KEYLEN - real_size);
424 err = grub_zfs_add_key (buf);
425 if (err)
426 return err;
427 return GRUB_ERR_NONE;
428 }
429
430 if (ctxt->state[1].set)
431 {
432 int i;
433 grub_err_t err;
434 if (real_size < 2 * GRUB_ZFS_MAX_KEYLEN)
435 grub_memset (buf + real_size, '0', 2 * GRUB_ZFS_MAX_KEYLEN - real_size);
436 for (i = 0; i < GRUB_ZFS_MAX_KEYLEN; i++)
437 {
438 char c1 = grub_tolower (buf[2 * i]) - '0';
439 char c2 = grub_tolower (buf[2 * i + 1]) - '0';
440 if (c1 > 9)
441 c1 += '0' - 'a' + 10;
442 if (c2 > 9)
443 c2 += '0' - 'a' + 10;
444 buf[i] = (c1 << 4) | c2;
445 }
446 err = grub_zfs_add_key (buf);
447 if (err)
448 return err;
449 return GRUB_ERR_NONE;
450 }
451 return GRUB_ERR_NONE;
452 }
453
454 static grub_command_t cmd_info, cmd_bootfs;
455 static grub_extcmd_t cmd_key;
456
457 GRUB_MOD_INIT (zfsinfo)
458 {
459 cmd_info = grub_register_command ("zfsinfo", grub_cmd_zfsinfo,
460 "zfsinfo DEVICE",
461 "Print ZFS info about DEVICE.");
462 cmd_key = grub_register_extcmd ("zfskey", grub_cmd_zfs_key, 0,
463 "zfskey [-h|-p|-r] [FILE]",
464 "Import ZFS wrapping key stored in FILE.",
465 options);
466 cmd_bootfs = grub_register_command ("zfs-bootfs", grub_cmd_zfs_bootfs,
467 "zfs-bootfs FILESYSTEM [VARIABLE]",
468 "Print ZFS-BOOTFSOBJ or set it to VARIABLE");
469 }
470
471 GRUB_MOD_FINI (zfsinfo)
472 {
473 grub_unregister_command (cmd_info);
474 grub_unregister_command (cmd_bootfs);
475 grub_unregister_extcmd (cmd_key);
476 }