]>
Commit | Line | Data |
---|---|---|
ddd5cee9 | 1 | /* grub-probe.c - probe device information for a given path */ |
8b5f3938 | 2 | /* |
3 | * GRUB -- GRand Unified Bootloader | |
2f1a3acf | 4 | * Copyright (C) 2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc. |
8b5f3938 | 5 | * |
5a79f472 | 6 | * GRUB is free software: you can redistribute it and/or modify |
8b5f3938 | 7 | * it under the terms of the GNU General Public License as published by |
5a79f472 | 8 | * the Free Software Foundation, either version 3 of the License, or |
8b5f3938 | 9 | * (at your option) any later version. |
10 | * | |
5a79f472 | 11 | * GRUB is distributed in the hope that it will be useful, |
8b5f3938 | 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 | |
5a79f472 | 17 | * along with GRUB. If not, see <http://www.gnu.org/licenses/>. |
8b5f3938 | 18 | */ |
19 | ||
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> | |
2a9525e6 | 25 | #include <grub/file.h> |
8b5f3938 | 26 | #include <grub/fs.h> |
27 | #include <grub/partition.h> | |
71acf5e5 | 28 | #include <grub/msdos_partition.h> |
ddbf5556 | 29 | #include <grub/util/hostdisk.h> |
8b5f3938 | 30 | #include <grub/util/getroot.h> |
9cacaa17 | 31 | #include <grub/term.h> |
0bf6d401 | 32 | #include <grub/env.h> |
f45d6cfc | 33 | #include <grub/raid.h> |
8a4c07fd | 34 | #include <grub/i18n.h> |
8b5f3938 | 35 | |
daf0f0ba | 36 | #include <grub_probe_init.h> |
37 | ||
8b5f3938 | 38 | #include <stdio.h> |
39 | #include <unistd.h> | |
40 | #include <string.h> | |
41 | #include <stdlib.h> | |
2a9525e6 | 42 | #include <sys/stat.h> |
8b5f3938 | 43 | |
44 | #define _GNU_SOURCE 1 | |
45 | #include <getopt.h> | |
46 | ||
8a4c07fd RM |
47 | #include "progname.h" |
48 | ||
1eb8c802 | 49 | enum { |
50 | PRINT_FS, | |
62191274 | 51 | PRINT_FS_UUID, |
1eb8c802 | 52 | PRINT_DRIVE, |
53 | PRINT_DEVICE, | |
54 | PRINT_PARTMAP, | |
55 | PRINT_ABSTRACTION, | |
56 | }; | |
ddd5cee9 | 57 | |
58 | int print = PRINT_FS; | |
79ca2d78 | 59 | static unsigned int argument_is_device = 0; |
ddd5cee9 | 60 | |
8b5f3938 | 61 | void |
62 | grub_putchar (int c) | |
63 | { | |
64 | putchar (c); | |
65 | } | |
66 | ||
9cacaa17 | 67 | int |
68 | grub_getkey (void) | |
69 | { | |
70 | return -1; | |
71 | } | |
72 | ||
71b9f361 | 73 | struct grub_handler_class grub_term_input_class; |
74 | struct grub_handler_class grub_term_output_class; | |
9cacaa17 | 75 | |
8b5f3938 | 76 | void |
77 | grub_refresh (void) | |
78 | { | |
6cf12cbd | 79 | fflush (stdout); |
8b5f3938 | 80 | } |
81 | ||
b92f0c18 | 82 | static void |
83 | probe_partmap (grub_disk_t disk) | |
84 | { | |
15cb7d43 VS |
85 | grub_partition_t part; |
86 | ||
b92f0c18 | 87 | if (disk->partition == NULL) |
88 | { | |
70a14d3d | 89 | grub_util_info ("no partition map found for %s", disk->name); |
b92f0c18 | 90 | return; |
91 | } | |
b39f9d20 | 92 | |
15cb7d43 VS |
93 | for (part = disk->partition; part; part = part->parent) |
94 | printf ("%s\n", part->partmap->name); | |
b92f0c18 | 95 | } |
96 | ||
f45d6cfc | 97 | static int |
98 | probe_raid_level (grub_disk_t disk) | |
99 | { | |
917dd370 CW |
100 | /* disk might be NULL in the case of a LVM physical volume with no LVM |
101 | signature. Ignore such cases here. */ | |
102 | if (!disk) | |
103 | return -1; | |
104 | ||
f45d6cfc | 105 | if (disk->dev->id != GRUB_DISK_DEVICE_RAID_ID) |
106 | return -1; | |
107 | ||
108 | return ((struct grub_raid_array *) disk->data)->level; | |
109 | } | |
110 | ||
8b5f3938 | 111 | static void |
79ca2d78 | 112 | probe (const char *path, char *device_name) |
8b5f3938 | 113 | { |
0215dcbf | 114 | char *drive_name = NULL; |
2a9525e6 | 115 | char *grub_path = NULL; |
116 | char *filebuf_via_grub = NULL, *filebuf_via_sys = NULL; | |
2a9525e6 | 117 | grub_device_t dev = NULL; |
62191274 | 118 | grub_fs_t fs; |
b39f9d20 | 119 | |
79ca2d78 | 120 | if (path == NULL) |
121 | { | |
e0fc9e78 | 122 | #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) |
b1ac8644 | 123 | if (! grub_util_check_char_device (device_name)) |
70a14d3d | 124 | grub_util_error ("%s is not a character device", device_name); |
b1ac8644 | 125 | #else |
79ca2d78 | 126 | if (! grub_util_check_block_device (device_name)) |
70a14d3d | 127 | grub_util_error ("%s is not a block device", device_name); |
b1ac8644 | 128 | #endif |
79ca2d78 | 129 | } |
130 | else | |
131 | device_name = grub_guess_root_device (path); | |
132 | ||
8b5f3938 | 133 | if (! device_name) |
70a14d3d | 134 | grub_util_error ("cannot find a device for %s (is /dev mounted?)", path); |
ddd5cee9 | 135 | |
136 | if (print == PRINT_DEVICE) | |
137 | { | |
138 | printf ("%s\n", device_name); | |
e0994b8b | 139 | goto end; |
ddd5cee9 | 140 | } |
141 | ||
849d55d3 | 142 | drive_name = grub_util_get_grub_dev (device_name); |
143 | if (! drive_name) | |
70a14d3d | 144 | grub_util_error ("cannot find a GRUB drive for %s. Check your device.map", device_name); |
b39f9d20 | 145 | |
ddd5cee9 | 146 | if (print == PRINT_DRIVE) |
147 | { | |
148 | printf ("(%s)\n", drive_name); | |
e0994b8b | 149 | goto end; |
8b5f3938 | 150 | } |
151 | ||
e0994b8b | 152 | grub_util_info ("opening %s", drive_name); |
153 | dev = grub_device_open (drive_name); | |
8b5f3938 | 154 | if (! dev) |
155 | grub_util_error ("%s", grub_errmsg); | |
156 | ||
f45d6cfc | 157 | if (print == PRINT_ABSTRACTION) |
158 | { | |
159 | grub_disk_memberlist_t list = NULL, tmp; | |
160 | const int is_lvm = (dev->disk->dev->id == GRUB_DISK_DEVICE_LVM_ID); | |
161 | int is_raid = 0; | |
162 | int is_raid5 = 0; | |
163 | int is_raid6 = 0; | |
164 | int raid_level; | |
165 | ||
166 | raid_level = probe_raid_level (dev->disk); | |
167 | if (raid_level >= 0) | |
168 | { | |
169 | is_raid = 1; | |
170 | is_raid5 |= (raid_level == 5); | |
171 | is_raid6 |= (raid_level == 6); | |
172 | } | |
173 | ||
174 | if ((is_lvm) && (dev->disk->dev->memberlist)) | |
175 | list = dev->disk->dev->memberlist (dev->disk); | |
176 | while (list) | |
177 | { | |
178 | raid_level = probe_raid_level (list->disk); | |
179 | if (raid_level >= 0) | |
180 | { | |
181 | is_raid = 1; | |
182 | is_raid5 |= (raid_level == 5); | |
183 | is_raid6 |= (raid_level == 6); | |
184 | } | |
185 | ||
186 | tmp = list->next; | |
187 | free (list); | |
188 | list = tmp; | |
189 | } | |
190 | ||
191 | if (is_raid) | |
192 | { | |
193 | printf ("raid "); | |
194 | if (is_raid5) | |
195 | printf ("raid5rec "); | |
196 | if (is_raid6) | |
197 | printf ("raid6rec "); | |
198 | printf ("mdraid "); | |
199 | } | |
200 | ||
201 | if (is_lvm) | |
202 | printf ("lvm "); | |
203 | ||
204 | printf ("\n"); | |
205 | ||
206 | goto end; | |
207 | } | |
208 | ||
75f396cc | 209 | if (print == PRINT_PARTMAP) |
210 | { | |
b92f0c18 | 211 | grub_disk_memberlist_t list = NULL, tmp; |
212 | ||
213 | /* Check if dev->disk itself is contained in a partmap. */ | |
214 | probe_partmap (dev->disk); | |
215 | ||
216 | /* In case of LVM/RAID, check the member devices as well. */ | |
217 | if (dev->disk->dev->memberlist) | |
218 | list = dev->disk->dev->memberlist (dev->disk); | |
219 | while (list) | |
220 | { | |
221 | probe_partmap (list->disk); | |
f45d6cfc | 222 | /* LVM on RAID */ |
223 | if (list->disk->dev->memberlist) | |
224 | { | |
225 | grub_disk_memberlist_t sub_list; | |
226 | ||
227 | sub_list = list->disk->dev->memberlist (list->disk); | |
228 | while (sub_list) | |
229 | { | |
230 | probe_partmap (sub_list->disk); | |
231 | tmp = sub_list->next; | |
232 | free (sub_list); | |
233 | sub_list = tmp; | |
234 | } | |
235 | } | |
b92f0c18 | 236 | tmp = list->next; |
237 | free (list); | |
238 | list = tmp; | |
239 | } | |
75f396cc | 240 | goto end; |
241 | } | |
242 | ||
62191274 | 243 | fs = grub_fs_probe (dev); |
244 | if (! fs) | |
245 | grub_util_error ("%s", grub_errmsg); | |
246 | ||
2a9525e6 | 247 | if (print == PRINT_FS) |
248 | { | |
dc9837ea ST |
249 | if (path) |
250 | { | |
251 | struct stat st; | |
8b5f3938 | 252 | |
dc9837ea | 253 | stat (path, &st); |
2a9525e6 | 254 | |
dc9837ea ST |
255 | if (S_ISREG (st.st_mode)) |
256 | { | |
257 | /* Regular file. Verify that we can read it properly. */ | |
258 | ||
259 | grub_file_t file; | |
260 | char *rel_path; | |
261 | grub_util_info ("reading %s via OS facilities", path); | |
262 | filebuf_via_sys = grub_util_read_image (path); | |
263 | ||
264 | rel_path = make_system_path_relative_to_its_root (path); | |
d6ceebf1 | 265 | grub_path = xasprintf ("(%s)%s", drive_name, rel_path); |
dc9837ea ST |
266 | free (rel_path); |
267 | grub_util_info ("reading %s via GRUB facilities", grub_path); | |
268 | file = grub_file_open (grub_path); | |
269 | if (! file) | |
61ba42be | 270 | grub_util_error ("cannot open %s via GRUB facilities", grub_path); |
dc9837ea ST |
271 | filebuf_via_grub = xmalloc (file->size); |
272 | grub_file_read (file, filebuf_via_grub, file->size); | |
273 | ||
274 | grub_util_info ("comparing"); | |
275 | ||
276 | if (memcmp (filebuf_via_grub, filebuf_via_sys, file->size)) | |
277 | grub_util_error ("files differ"); | |
278 | } | |
2a9525e6 | 279 | } |
7f26d466 | 280 | |
2a9525e6 | 281 | printf ("%s\n", fs->name); |
282 | } | |
e0994b8b | 283 | |
62191274 | 284 | if (print == PRINT_FS_UUID) |
285 | { | |
286 | char *uuid; | |
287 | if (! fs->uuid) | |
288 | grub_util_error ("%s does not support UUIDs", fs->name); | |
289 | ||
290 | fs->uuid (dev, &uuid); | |
291 | ||
292 | printf ("%s\n", uuid); | |
293 | } | |
294 | ||
e0994b8b | 295 | end: |
2a9525e6 | 296 | if (dev) |
297 | grub_device_close (dev); | |
298 | free (grub_path); | |
299 | free (filebuf_via_grub); | |
300 | free (filebuf_via_sys); | |
e0994b8b | 301 | free (drive_name); |
8b5f3938 | 302 | } |
303 | ||
304 | static struct option options[] = | |
305 | { | |
79ca2d78 | 306 | {"device", no_argument, 0, 'd'}, |
8b5f3938 | 307 | {"device-map", required_argument, 0, 'm'}, |
ddd5cee9 | 308 | {"target", required_argument, 0, 't'}, |
8b5f3938 | 309 | {"help", no_argument, 0, 'h'}, |
310 | {"version", no_argument, 0, 'V'}, | |
311 | {"verbose", no_argument, 0, 'v'}, | |
312 | {0, 0, 0, 0} | |
313 | }; | |
314 | ||
315 | static void | |
316 | usage (int status) | |
317 | { | |
318 | if (status) | |
319 | fprintf (stderr, | |
70a14d3d | 320 | "Try `%s --help' for more information.\n", program_name); |
8b5f3938 | 321 | else |
322 | printf ("\ | |
8a4c07fd | 323 | Usage: %s [OPTION]... [PATH|DEVICE]\n\ |
8b5f3938 | 324 | \n\ |
79ca2d78 | 325 | Probe device information for a given path (or device, if the -d option is given).\n\ |
8b5f3938 | 326 | \n\ |
79ca2d78 | 327 | -d, --device given argument is a system device, not a path\n\ |
8b5f3938 | 328 | -m, --device-map=FILE use FILE as the device map [default=%s]\n\ |
62191274 | 329 | -t, --target=(fs|fs_uuid|drive|device|partmap|abstraction)\n\ |
1eb8c802 | 330 | print filesystem module, GRUB drive, system device, partition map module or abstraction module [default=fs]\n\ |
8b5f3938 | 331 | -h, --help display this message and exit\n\ |
332 | -V, --version print version information and exit\n\ | |
333 | -v, --verbose print verbose messages\n\ | |
334 | \n\ | |
335 | Report bugs to <%s>.\n\ | |
8a4c07fd | 336 | ", program_name, |
8b5f3938 | 337 | DEFAULT_DEVICE_MAP, PACKAGE_BUGREPORT); |
b39f9d20 | 338 | |
8b5f3938 | 339 | exit (status); |
340 | } | |
341 | ||
342 | int | |
343 | main (int argc, char *argv[]) | |
344 | { | |
345 | char *dev_map = 0; | |
79ca2d78 | 346 | char *argument; |
b39f9d20 | 347 | |
8a4c07fd | 348 | set_program_name (argv[0]); |
2f1a3acf YB |
349 | |
350 | grub_util_init_nls (); | |
b39f9d20 | 351 | |
8b5f3938 | 352 | /* Check for options. */ |
353 | while (1) | |
354 | { | |
79ca2d78 | 355 | int c = getopt_long (argc, argv, "dm:t:hVv", options, 0); |
b39f9d20 | 356 | |
8b5f3938 | 357 | if (c == -1) |
358 | break; | |
359 | else | |
360 | switch (c) | |
361 | { | |
79ca2d78 | 362 | case 'd': |
363 | argument_is_device = 1; | |
364 | break; | |
365 | ||
8b5f3938 | 366 | case 'm': |
367 | if (dev_map) | |
368 | free (dev_map); | |
369 | ||
370 | dev_map = xstrdup (optarg); | |
371 | break; | |
372 | ||
ddd5cee9 | 373 | case 't': |
374 | if (!strcmp (optarg, "fs")) | |
375 | print = PRINT_FS; | |
62191274 | 376 | else if (!strcmp (optarg, "fs_uuid")) |
377 | print = PRINT_FS_UUID; | |
ddd5cee9 | 378 | else if (!strcmp (optarg, "drive")) |
379 | print = PRINT_DRIVE; | |
380 | else if (!strcmp (optarg, "device")) | |
381 | print = PRINT_DEVICE; | |
75f396cc | 382 | else if (!strcmp (optarg, "partmap")) |
383 | print = PRINT_PARTMAP; | |
1eb8c802 | 384 | else if (!strcmp (optarg, "abstraction")) |
385 | print = PRINT_ABSTRACTION; | |
ddd5cee9 | 386 | else |
387 | usage (1); | |
388 | break; | |
389 | ||
8b5f3938 | 390 | case 'h': |
391 | usage (0); | |
392 | break; | |
393 | ||
394 | case 'V': | |
8a4c07fd | 395 | printf ("%s (%s) %s\n", program_name, PACKAGE_NAME, PACKAGE_VERSION); |
8b5f3938 | 396 | return 0; |
397 | ||
398 | case 'v': | |
399 | verbosity++; | |
400 | break; | |
401 | ||
402 | default: | |
403 | usage (1); | |
404 | break; | |
405 | } | |
406 | } | |
407 | ||
91a4bf68 | 408 | if (verbosity > 1) |
409 | grub_env_set ("debug", "all"); | |
410 | ||
79ca2d78 | 411 | /* Obtain ARGUMENT. */ |
8b5f3938 | 412 | if (optind >= argc) |
413 | { | |
79ca2d78 | 414 | fprintf (stderr, "No path or device is specified.\n"); |
8b5f3938 | 415 | usage (1); |
416 | } | |
417 | ||
418 | if (optind + 1 != argc) | |
419 | { | |
420 | fprintf (stderr, "Unknown extra argument `%s'.\n", argv[optind + 1]); | |
421 | usage (1); | |
422 | } | |
423 | ||
79ca2d78 | 424 | argument = argv[optind]; |
b39f9d20 | 425 | |
8b5f3938 | 426 | /* Initialize the emulated biosdisk driver. */ |
427 | grub_util_biosdisk_init (dev_map ? : DEFAULT_DEVICE_MAP); | |
b39f9d20 | 428 | |
daf0f0ba | 429 | /* Initialize all modules. */ |
430 | grub_init_all (); | |
8b5f3938 | 431 | |
432 | /* Do it. */ | |
79ca2d78 | 433 | if (argument_is_device) |
434 | probe (NULL, argument); | |
435 | else | |
436 | probe (argument, NULL); | |
b39f9d20 | 437 | |
8b5f3938 | 438 | /* Free resources. */ |
daf0f0ba | 439 | grub_fini_all (); |
8b5f3938 | 440 | grub_util_biosdisk_fini (); |
b39f9d20 | 441 | |
8b5f3938 | 442 | free (dev_map); |
b39f9d20 | 443 | |
8b5f3938 | 444 | return 0; |
445 | } |