2009-04-17 Pavel Roskin <proski@gnu.org>
[grub2/bean.git] / util / grub-probe.c
blobbdb9159641737fe16523d422fdc2fb617632409b
1 /* grub-probe.c - probe device information for a given path */
2 /*
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2005,2006,2007,2008,2009 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/>.
20 #include <config.h>
21 #include <grub/types.h>
22 #include <grub/util/misc.h>
23 #include <grub/device.h>
24 #include <grub/disk.h>
25 #include <grub/file.h>
26 #include <grub/fs.h>
27 #include <grub/partition.h>
28 #include <grub/pc_partition.h>
29 #include <grub/util/hostdisk.h>
30 #include <grub/util/getroot.h>
31 #include <grub/term.h>
32 #include <grub/env.h>
34 #include <grub_probe_init.h>
36 #include <stdio.h>
37 #include <unistd.h>
38 #include <string.h>
39 #include <stdlib.h>
40 #include <sys/stat.h>
42 #define _GNU_SOURCE 1
43 #include <getopt.h>
45 enum {
46 PRINT_FS,
47 PRINT_FS_UUID,
48 PRINT_DRIVE,
49 PRINT_DEVICE,
50 PRINT_PARTMAP,
51 PRINT_ABSTRACTION,
54 int print = PRINT_FS;
55 static unsigned int argument_is_device = 0;
57 void
58 grub_putchar (int c)
60 putchar (c);
63 int
64 grub_getkey (void)
66 return -1;
69 struct grub_handler_class grub_term_input_class;
70 struct grub_handler_class grub_term_output_class;
72 void
73 grub_refresh (void)
75 fflush (stdout);
78 static void
79 probe_partmap (grub_disk_t disk)
81 char *name;
82 char *underscore;
84 if (disk->partition == NULL)
86 grub_util_info ("No partition map found for %s", disk->name);
87 return;
90 name = strdup (disk->partition->partmap->name);
91 if (! name)
92 grub_util_error ("Not enough memory");
94 underscore = strchr (name, '_');
95 if (! underscore)
96 grub_util_error ("Invalid partition map %s", name);
98 *underscore = '\0';
99 printf ("%s\n", name);
100 free (name);
103 static void
104 probe (const char *path, char *device_name)
106 char *drive_name = NULL;
107 char *grub_path = NULL;
108 char *filebuf_via_grub = NULL, *filebuf_via_sys = NULL;
109 int abstraction_type;
110 grub_device_t dev = NULL;
111 grub_fs_t fs;
113 if (path == NULL)
115 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
116 if (! grub_util_check_char_device (device_name))
117 grub_util_error ("%s is not a character device.\n", device_name);
118 #else
119 if (! grub_util_check_block_device (device_name))
120 grub_util_error ("%s is not a block device.\n", device_name);
121 #endif
123 else
124 device_name = grub_guess_root_device (path);
126 if (! device_name)
127 grub_util_error ("cannot find a device for %s.\n", path);
129 if (print == PRINT_DEVICE)
131 printf ("%s\n", device_name);
132 goto end;
135 abstraction_type = grub_util_get_dev_abstraction (device_name);
136 /* No need to check for errors; lack of abstraction is permissible. */
138 if (print == PRINT_ABSTRACTION)
140 char *abstraction_name;
141 switch (abstraction_type)
143 case GRUB_DEV_ABSTRACTION_LVM:
144 abstraction_name = "lvm";
145 break;
146 case GRUB_DEV_ABSTRACTION_RAID:
147 abstraction_name = "raid mdraid";
148 break;
149 default:
150 grub_util_info ("did not find LVM/RAID in %s, assuming raw device", device_name);
151 goto end;
153 printf ("%s\n", abstraction_name);
154 goto end;
157 drive_name = grub_util_get_grub_dev (device_name);
158 if (! drive_name)
159 grub_util_error ("Cannot find a GRUB drive for %s. Check your device.map.\n", device_name);
161 if (print == PRINT_DRIVE)
163 printf ("(%s)\n", drive_name);
164 goto end;
167 grub_util_info ("opening %s", drive_name);
168 dev = grub_device_open (drive_name);
169 if (! dev)
170 grub_util_error ("%s", grub_errmsg);
172 if (print == PRINT_PARTMAP)
174 grub_disk_memberlist_t list = NULL, tmp;
176 /* Check if dev->disk itself is contained in a partmap. */
177 probe_partmap (dev->disk);
179 /* In case of LVM/RAID, check the member devices as well. */
180 if (dev->disk->dev->memberlist)
181 list = dev->disk->dev->memberlist (dev->disk);
182 while (list)
184 probe_partmap (list->disk);
185 tmp = list->next;
186 free (list);
187 list = tmp;
189 goto end;
192 fs = grub_fs_probe (dev);
193 if (! fs)
194 grub_util_error ("%s", grub_errmsg);
196 if (print == PRINT_FS)
198 struct stat st;
200 stat (path, &st);
202 if (st.st_mode == S_IFREG)
204 /* Regular file. Verify that we can read it properly. */
206 grub_file_t file;
207 grub_util_info ("reading %s via OS facilities", path);
208 filebuf_via_sys = grub_util_read_image (path);
210 grub_util_info ("reading %s via GRUB facilities", path);
211 asprintf (&grub_path, "(%s)%s", drive_name, path);
212 file = grub_file_open (grub_path);
213 filebuf_via_grub = xmalloc (file->size);
214 grub_file_read (file, filebuf_via_grub, file->size);
216 grub_util_info ("comparing");
218 if (memcmp (filebuf_via_grub, filebuf_via_sys, file->size))
219 grub_util_error ("files differ");
221 printf ("%s\n", fs->name);
224 if (print == PRINT_FS_UUID)
226 char *uuid;
227 if (! fs->uuid)
228 grub_util_error ("%s does not support UUIDs", fs->name);
230 fs->uuid (dev, &uuid);
232 printf ("%s\n", uuid);
235 end:
236 if (dev)
237 grub_device_close (dev);
238 free (grub_path);
239 free (filebuf_via_grub);
240 free (filebuf_via_sys);
241 free (drive_name);
244 static struct option options[] =
246 {"device", no_argument, 0, 'd'},
247 {"device-map", required_argument, 0, 'm'},
248 {"target", required_argument, 0, 't'},
249 {"help", no_argument, 0, 'h'},
250 {"version", no_argument, 0, 'V'},
251 {"verbose", no_argument, 0, 'v'},
252 {0, 0, 0, 0}
255 static void
256 usage (int status)
258 if (status)
259 fprintf (stderr,
260 "Try ``grub-probe --help'' for more information.\n");
261 else
262 printf ("\
263 Usage: grub-probe [OPTION]... [PATH|DEVICE]\n\
265 Probe device information for a given path (or device, if the -d option is given).\n\
267 -d, --device given argument is a system device, not a path\n\
268 -m, --device-map=FILE use FILE as the device map [default=%s]\n\
269 -t, --target=(fs|fs_uuid|drive|device|partmap|abstraction)\n\
270 print filesystem module, GRUB drive, system device, partition map module or abstraction module [default=fs]\n\
271 -h, --help display this message and exit\n\
272 -V, --version print version information and exit\n\
273 -v, --verbose print verbose messages\n\
275 Report bugs to <%s>.\n\
277 DEFAULT_DEVICE_MAP, PACKAGE_BUGREPORT);
279 exit (status);
283 main (int argc, char *argv[])
285 char *dev_map = 0;
286 char *argument;
288 progname = "grub-probe";
290 /* Check for options. */
291 while (1)
293 int c = getopt_long (argc, argv, "dm:t:hVv", options, 0);
295 if (c == -1)
296 break;
297 else
298 switch (c)
300 case 'd':
301 argument_is_device = 1;
302 break;
304 case 'm':
305 if (dev_map)
306 free (dev_map);
308 dev_map = xstrdup (optarg);
309 break;
311 case 't':
312 if (!strcmp (optarg, "fs"))
313 print = PRINT_FS;
314 else if (!strcmp (optarg, "fs_uuid"))
315 print = PRINT_FS_UUID;
316 else if (!strcmp (optarg, "drive"))
317 print = PRINT_DRIVE;
318 else if (!strcmp (optarg, "device"))
319 print = PRINT_DEVICE;
320 else if (!strcmp (optarg, "partmap"))
321 print = PRINT_PARTMAP;
322 else if (!strcmp (optarg, "abstraction"))
323 print = PRINT_ABSTRACTION;
324 else
325 usage (1);
326 break;
328 case 'h':
329 usage (0);
330 break;
332 case 'V':
333 printf ("%s (%s) %s\n", progname, PACKAGE_NAME, PACKAGE_VERSION);
334 return 0;
336 case 'v':
337 verbosity++;
338 break;
340 default:
341 usage (1);
342 break;
346 if (verbosity > 1)
347 grub_env_set ("debug", "all");
349 /* Obtain ARGUMENT. */
350 if (optind >= argc)
352 fprintf (stderr, "No path or device is specified.\n");
353 usage (1);
356 if (optind + 1 != argc)
358 fprintf (stderr, "Unknown extra argument `%s'.\n", argv[optind + 1]);
359 usage (1);
362 argument = argv[optind];
364 /* Initialize the emulated biosdisk driver. */
365 grub_util_biosdisk_init (dev_map ? : DEFAULT_DEVICE_MAP);
367 /* Initialize all modules. */
368 grub_init_all ();
370 /* Do it. */
371 if (argument_is_device)
372 probe (NULL, argument);
373 else
374 probe (argument, NULL);
376 /* Free resources. */
377 grub_fini_all ();
378 grub_util_biosdisk_fini ();
380 free (dev_map);
382 return 0;