Upgraded GRUB2 to 2.00 release.
[AROS.git] / arch / all-pc / boot / grub2-aros / util / grub-mount.c
blobe3eb1d7f3ee8e4b580d1a61a7964a27718e53906
1 /* grub-mount.c - FUSE driver for filesystems that GRUB understands */
2 /*
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2008,2009,2010 Free Software Foundation, Inc.
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.
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.
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/>.
19 #define FUSE_USE_VERSION 26
20 #include <config.h>
21 #include <grub/types.h>
22 #include <grub/emu/misc.h>
23 #include <grub/util/misc.h>
24 #include <grub/misc.h>
25 #include <grub/device.h>
26 #include <grub/disk.h>
27 #include <grub/file.h>
28 #include <grub/fs.h>
29 #include <grub/env.h>
30 #include <grub/term.h>
31 #include <grub/mm.h>
32 #include <grub/lib/hexdump.h>
33 #include <grub/crypto.h>
34 #include <grub/command.h>
35 #include <grub/zfs/zfs.h>
36 #include <grub/i18n.h>
37 #include <fuse/fuse.h>
39 #include <stdio.h>
40 #include <unistd.h>
41 #include <string.h>
42 #include <stdlib.h>
44 #include "progname.h"
45 #include "argp.h"
47 static const char *root = NULL;
48 grub_device_t dev = NULL;
49 grub_fs_t fs = NULL;
50 static char **images = NULL;
51 static char *debug_str = NULL;
52 static char **fuse_args = NULL;
53 static int fuse_argc = 0;
54 static int num_disks = 0;
55 static int mount_crypt = 0;
57 static grub_err_t
58 execute_command (const char *name, int n, char **args)
60 grub_command_t cmd;
62 cmd = grub_command_find (name);
63 if (! cmd)
64 grub_util_error (_("can't find command `%s'"), name);
66 return (cmd->func) (cmd, n, args);
69 /* Translate GRUB error numbers into OS error numbers. Print any unexpected
70 errors. */
71 static int
72 translate_error (void)
74 int ret;
76 switch (grub_errno)
78 case GRUB_ERR_NONE:
79 ret = 0;
80 break;
82 case GRUB_ERR_OUT_OF_MEMORY:
83 grub_print_error ();
84 ret = -ENOMEM;
85 break;
87 case GRUB_ERR_BAD_FILE_TYPE:
88 /* This could also be EISDIR. Take a guess. */
89 ret = -ENOTDIR;
90 break;
92 case GRUB_ERR_FILE_NOT_FOUND:
93 ret = -ENOENT;
94 break;
96 case GRUB_ERR_FILE_READ_ERROR:
97 case GRUB_ERR_READ_ERROR:
98 case GRUB_ERR_IO:
99 grub_print_error ();
100 ret = -EIO;
101 break;
103 case GRUB_ERR_SYMLINK_LOOP:
104 ret = -ELOOP;
105 break;
107 default:
108 grub_print_error ();
109 ret = -EINVAL;
110 break;
113 /* Any previous errors were handled. */
114 grub_errno = GRUB_ERR_NONE;
116 return ret;
119 static int
120 fuse_getattr (const char *path, struct stat *st)
122 char *filename, *pathname, *path2;
123 const char *pathname_t;
124 struct grub_dirhook_info file_info;
125 int file_exists = 0;
127 /* A hook for iterating directories. */
128 auto int find_file (const char *cur_filename,
129 const struct grub_dirhook_info *info);
130 int find_file (const char *cur_filename,
131 const struct grub_dirhook_info *info)
133 if ((info->case_insensitive ? grub_strcasecmp (cur_filename, filename)
134 : grub_strcmp (cur_filename, filename)) == 0)
136 file_info = *info;
137 file_exists = 1;
138 return 1;
140 return 0;
143 if (path[0] == '/' && path[1] == 0)
145 st->st_dev = 0;
146 st->st_ino = 0;
147 st->st_mode = 0555 | S_IFDIR;
148 st->st_uid = 0;
149 st->st_gid = 0;
150 st->st_rdev = 0;
151 st->st_size = 0;
152 st->st_blksize = 512;
153 st->st_blocks = (st->st_blksize + 511) >> 9;
154 st->st_atime = st->st_mtime = st->st_ctime = 0;
155 return 0;
158 file_exists = 0;
160 pathname_t = grub_strchr (path, ')');
161 if (! pathname_t)
162 pathname_t = path;
163 else
164 pathname_t++;
165 pathname = xstrdup (pathname_t);
167 /* Remove trailing '/'. */
168 while (*pathname && pathname[grub_strlen (pathname) - 1] == '/')
169 pathname[grub_strlen (pathname) - 1] = 0;
171 /* Split into path and filename. */
172 filename = grub_strrchr (pathname, '/');
173 if (! filename)
175 path2 = grub_strdup ("/");
176 filename = pathname;
178 else
180 filename++;
181 path2 = grub_strdup (pathname);
182 path2[filename - pathname] = 0;
185 /* It's the whole device. */
186 (fs->dir) (dev, path2, find_file);
188 grub_free (path2);
189 if (!file_exists)
191 grub_errno = GRUB_ERR_NONE;
192 return -ENOENT;
194 st->st_dev = 0;
195 st->st_ino = 0;
196 st->st_mode = file_info.dir ? (0555 | S_IFDIR) : (0444 | S_IFREG);
197 st->st_uid = 0;
198 st->st_gid = 0;
199 st->st_rdev = 0;
200 if (!file_info.dir)
202 grub_file_t file;
203 file = grub_file_open (path);
204 if (! file)
205 return translate_error ();
206 st->st_size = file->size;
207 grub_file_close (file);
209 else
210 st->st_size = 0;
211 st->st_blksize = 512;
212 st->st_blocks = (st->st_size + 511) >> 9;
213 st->st_atime = st->st_mtime = st->st_ctime = file_info.mtimeset
214 ? file_info.mtime : 0;
215 grub_errno = GRUB_ERR_NONE;
216 return 0;
219 static int
220 fuse_opendir (const char *path, struct fuse_file_info *fi)
222 return 0;
225 /* FIXME */
226 static grub_file_t files[65536];
227 static int first_fd = 1;
229 static int
230 fuse_open (const char *path, struct fuse_file_info *fi __attribute__ ((unused)))
232 grub_file_t file;
233 file = grub_file_open (path);
234 if (! file)
235 return translate_error ();
236 files[first_fd++] = file;
237 fi->fh = first_fd;
238 files[first_fd++] = file;
239 grub_errno = GRUB_ERR_NONE;
240 return 0;
243 static int
244 fuse_read (const char *path, char *buf, size_t sz, off_t off,
245 struct fuse_file_info *fi)
247 grub_file_t file = files[fi->fh];
248 grub_ssize_t size;
250 if (off > file->size)
251 return -EINVAL;
253 file->offset = off;
255 size = grub_file_read (file, buf, sz);
256 if (size < 0)
257 return translate_error ();
258 else
260 grub_errno = GRUB_ERR_NONE;
261 return size;
265 static int
266 fuse_release (const char *path, struct fuse_file_info *fi)
268 grub_file_close (files[fi->fh]);
269 files[fi->fh] = NULL;
270 grub_errno = GRUB_ERR_NONE;
271 return 0;
274 static int
275 fuse_readdir (const char *path, void *buf,
276 fuse_fill_dir_t fill, off_t off, struct fuse_file_info *fi)
278 char *pathname;
280 auto int call_fill (const char *filename,
281 const struct grub_dirhook_info *info);
282 int call_fill (const char *filename, const struct grub_dirhook_info *info)
284 struct stat st;
285 grub_memset (&st, 0, sizeof (st));
286 st.st_mode = info->dir ? (0555 | S_IFDIR) : (0444 | S_IFREG);
287 if (!info->dir)
289 grub_file_t file;
290 char *tmp;
291 tmp = xasprintf ("%s/%s", path, filename);
292 file = grub_file_open (tmp);
293 free (tmp);
294 if (! file)
295 return translate_error ();
296 st.st_size = file->size;
297 grub_file_close (file);
299 st.st_blksize = 512;
300 st.st_blocks = (st.st_size + 511) >> 9;
301 st.st_atime = st.st_mtime = st.st_ctime
302 = info->mtimeset ? info->mtime : 0;
303 fill (buf, filename, &st, 0);
304 return 0;
307 pathname = xstrdup (path);
309 /* Remove trailing '/'. */
310 while (pathname [0] && pathname[1]
311 && pathname[grub_strlen (pathname) - 1] == '/')
312 pathname[grub_strlen (pathname) - 1] = 0;
314 (fs->dir) (dev, pathname, call_fill);
315 free (pathname);
316 grub_errno = GRUB_ERR_NONE;
317 return 0;
320 struct fuse_operations grub_opers = {
321 .getattr = fuse_getattr,
322 .open = fuse_open,
323 .release = fuse_release,
324 .opendir = fuse_opendir,
325 .readdir = fuse_readdir,
326 .read = fuse_read
329 static grub_err_t
330 fuse_init (void)
332 int i;
334 for (i = 0; i < num_disks; i++)
336 char *argv[2];
337 char *host_file;
338 char *loop_name;
339 loop_name = grub_xasprintf ("loop%d", i);
340 if (!loop_name)
341 grub_util_error ("%s", grub_errmsg);
343 host_file = grub_xasprintf ("(host)%s", images[i]);
344 if (!host_file)
345 grub_util_error ("%s", grub_errmsg);
347 argv[0] = loop_name;
348 argv[1] = host_file;
350 if (execute_command ("loopback", 2, argv))
351 grub_util_error (_("`loopback' command fails: %s"), grub_errmsg);
353 grub_free (loop_name);
354 grub_free (host_file);
357 if (mount_crypt)
359 char *argv[2] = { xstrdup ("-a"), NULL};
360 if (execute_command ("cryptomount", 1, argv))
361 grub_util_error (_("`cryptomount' command fails: %s"),
362 grub_errmsg);
363 free (argv[0]);
366 grub_lvm_fini ();
367 grub_mdraid09_fini ();
368 grub_mdraid1x_fini ();
369 grub_diskfilter_fini ();
370 grub_diskfilter_init ();
371 grub_mdraid09_init ();
372 grub_mdraid1x_init ();
373 grub_lvm_init ();
375 dev = grub_device_open (0);
376 if (! dev)
377 return grub_errno;
379 fs = grub_fs_probe (dev);
380 if (! fs)
382 grub_device_close (dev);
383 return grub_errno;
386 fuse_main (fuse_argc, fuse_args, &grub_opers, NULL);
388 for (i = 0; i < num_disks; i++)
390 char *argv[2];
391 char *loop_name;
393 loop_name = grub_xasprintf ("loop%d", i);
394 if (!loop_name)
395 grub_util_error ("%s", grub_errmsg);
397 argv[0] = xstrdup ("-d");
398 argv[1] = loop_name;
400 execute_command ("loopback", 2, argv);
402 grub_free (argv[0]);
403 grub_free (loop_name);
406 return GRUB_ERR_NONE;
409 static struct argp_option options[] = {
410 {"root", 'r', N_("DEVICE_NAME"), 0, N_("Set root device."), 2},
411 {"debug", 'd', N_("STRING"), 0, N_("Set debug environment variable."), 2},
412 {"crypto", 'C', NULL, 0, N_("Mount crypto devices."), 2},
413 {"zfs-key", 'K',
414 /* TRANSLATORS: "prompt" is a keyword. */
415 N_("FILE|prompt"), 0, N_("Load zfs crypto key."), 2},
416 {"verbose", 'v', NULL, 0, N_("print verbose messages."), 2},
417 {0, 0, 0, 0, 0, 0}
420 /* Print the version information. */
421 static void
422 print_version (FILE *stream, struct argp_state *state)
424 fprintf (stream, "%s (%s) %s\n", program_name, PACKAGE_NAME, PACKAGE_VERSION);
426 void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
428 static error_t
429 argp_parser (int key, char *arg, struct argp_state *state)
431 switch (key)
433 case 'r':
434 root = arg;
435 return 0;
437 case 'K':
438 if (strcmp (arg, "prompt") == 0)
440 char buf[1024];
441 grub_printf ("%s", _("Enter ZFS password: "));
442 if (grub_password_get (buf, 1023))
444 grub_zfs_add_key ((grub_uint8_t *) buf, grub_strlen (buf), 1);
447 else
449 FILE *f;
450 ssize_t real_size;
451 grub_uint8_t buf[1024];
452 f = fopen (arg, "rb");
453 if (!f)
455 printf (_("%s: error:"), program_name);
456 printf (_("cannot open `%s': %s"), arg, strerror (errno));
457 printf ("\n");
458 return 0;
460 real_size = fread (buf, 1, 1024, f);
461 if (real_size < 0)
463 printf (_("%s: error:"), program_name);
464 printf (_("cannot read `%s': %s"), arg,
465 strerror (errno));
466 printf ("\n");
467 fclose (f);
468 return 0;
470 grub_zfs_add_key (buf, real_size, 0);
472 return 0;
474 case 'C':
475 mount_crypt = 1;
476 return 0;
478 case 'd':
479 debug_str = arg;
480 return 0;
482 case 'v':
483 verbosity++;
484 return 0;
486 case ARGP_KEY_ARG:
487 if (arg[0] != '-')
488 break;
490 default:
491 if (!arg)
492 return 0;
494 fuse_args = xrealloc (fuse_args, (fuse_argc + 1) * sizeof (fuse_args[0]));
495 fuse_args[fuse_argc] = xstrdup (arg);
496 fuse_argc++;
497 return 0;
500 images = xrealloc (images, (num_disks + 1) * sizeof (images[0]));
501 images[num_disks] = canonicalize_file_name (arg);
502 num_disks++;
504 return 0;
507 struct argp argp = {
508 options, argp_parser, N_("IMAGE1 [IMAGE2 ...] MOUNTPOINT"),
509 N_("Debug tool for filesystem driver."),
510 NULL, NULL, NULL
514 main (int argc, char *argv[])
516 const char *default_root;
517 char *alloc_root;
519 set_program_name (argv[0]);
521 grub_util_init_nls ();
523 fuse_args = xrealloc (fuse_args, (fuse_argc + 2) * sizeof (fuse_args[0]));
524 fuse_args[fuse_argc] = xstrdup (argv[0]);
525 fuse_argc++;
526 /* Run single-threaded. */
527 fuse_args[fuse_argc] = xstrdup ("-s");
528 fuse_argc++;
530 argp_parse (&argp, argc, argv, 0, 0, 0);
532 if (num_disks < 2)
533 grub_util_error ("%s", _("need an image and mountpoint"));
534 fuse_args = xrealloc (fuse_args, (fuse_argc + 2) * sizeof (fuse_args[0]));
535 fuse_args[fuse_argc] = images[num_disks - 1];
536 fuse_argc++;
537 num_disks--;
538 fuse_args[fuse_argc] = NULL;
540 /* Initialize all modules. */
541 grub_init_all ();
543 if (debug_str)
544 grub_env_set ("debug", debug_str);
546 default_root = (num_disks == 1) ? "loop0" : "md0";
547 alloc_root = 0;
548 if (root)
550 if ((*root >= '0') && (*root <= '9'))
552 alloc_root = xmalloc (strlen (default_root) + strlen (root) + 2);
554 sprintf (alloc_root, "%s,%s", default_root, root);
555 root = alloc_root;
558 else
559 root = default_root;
561 grub_env_set ("root", root);
563 if (alloc_root)
564 free (alloc_root);
566 /* Do it. */
567 fuse_init ();
568 if (grub_errno)
570 grub_print_error ();
571 return 1;
574 /* Free resources. */
575 grub_fini_all ();
577 return 0;