Indentation fix, cleanup.
[AROS.git] / arch / all-pc / boot / grub2-aros / util / getroot.c
blob3c1f12dca01b7fbeae137a2b59a750eec1835ed3
1 /* getroot.c - Get root device */
2 /*
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 1999,2000,2001,2002,2003,2006,2007,2008,2009,2010,2011 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-util.h>
21 #include <config.h>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25 #include <assert.h>
26 #include <fcntl.h>
27 #include <unistd.h>
28 #include <string.h>
29 #include <dirent.h>
30 #include <errno.h>
31 #include <error.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <stdint.h>
35 #ifdef HAVE_LIMITS_H
36 #include <limits.h>
37 #endif
38 #include <grub/util/misc.h>
40 #include <grub/cryptodisk.h>
41 #include <grub/i18n.h>
43 #ifdef __linux__
44 #include <sys/ioctl.h> /* ioctl */
45 #include <sys/mount.h>
46 #endif
48 #include <sys/types.h>
50 #if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR)
51 # include <grub/util/libzfs.h>
52 # include <grub/util/libnvpair.h>
53 #endif
55 #include <grub/mm.h>
56 #include <grub/misc.h>
57 #include <grub/emu/misc.h>
58 #include <grub/emu/hostdisk.h>
59 #include <grub/emu/getroot.h>
61 #if defined (__FreeBSD__) || defined (__FreeBSD_kernel__)
62 #include <sys/mount.h>
63 #endif
65 #if defined(__NetBSD__) || defined(__OpenBSD__)
66 # include <sys/ioctl.h>
67 # include <sys/disklabel.h> /* struct disklabel */
68 # include <sys/disk.h> /* struct dkwedge_info */
69 #include <sys/param.h>
70 #include <sys/mount.h>
71 #endif /* defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) */
73 #if defined(__NetBSD__)
74 # include <sys/fdio.h>
75 #endif
77 grub_disk_addr_t
78 grub_util_find_partition_start (const char *dev)
80 #if GRUB_UTIL_FD_STAT_IS_FUNCTIONAL
81 struct stat st;
82 grub_disk_addr_t partition_start;
84 if (stat (dev, &st) >= 0
85 && grub_util_device_is_mapped_stat (&st)
86 && grub_util_get_dm_node_linear_info (st.st_rdev, 0, 0, &partition_start))
87 return partition_start;
88 #endif
90 return grub_util_find_partition_start_os (dev);
93 void
94 grub_util_pull_device (const char *os_dev)
96 enum grub_dev_abstraction_types ab;
97 ab = grub_util_get_dev_abstraction (os_dev);
98 switch (ab)
100 case GRUB_DEV_ABSTRACTION_LVM:
101 grub_util_pull_lvm_by_command (os_dev);
102 /* Fallthrough in case that lvm-tools are unavailable. */
103 case GRUB_DEV_ABSTRACTION_LUKS:
104 grub_util_pull_devmapper (os_dev);
105 return;
107 default:
108 if (grub_util_pull_device_os (os_dev, ab))
109 return;
110 /* Fallthrough. */
111 case GRUB_DEV_ABSTRACTION_NONE:
112 free (grub_util_biosdisk_get_grub_dev (os_dev));
113 return;
117 char *
118 grub_util_get_grub_dev (const char *os_dev)
120 char *ret;
122 grub_util_pull_device (os_dev);
124 ret = grub_util_get_devmapper_grub_dev (os_dev);
125 if (ret)
126 return ret;
127 ret = grub_util_get_grub_dev_os (os_dev);
128 if (ret)
129 return ret;
130 return grub_util_biosdisk_get_grub_dev (os_dev);
134 grub_util_get_dev_abstraction (const char *os_dev)
136 enum grub_dev_abstraction_types ret;
138 /* User explicitly claims that this drive is visible by BIOS. */
139 if (grub_util_biosdisk_is_present (os_dev))
140 return GRUB_DEV_ABSTRACTION_NONE;
142 /* Check for LVM and LUKS. */
143 ret = grub_util_get_dm_abstraction (os_dev);
145 if (ret != GRUB_DEV_ABSTRACTION_NONE)
146 return ret;
148 return grub_util_get_dev_abstraction_os (os_dev);
151 static char *
152 convert_system_partition_to_system_disk (const char *os_dev, int *is_part)
154 #if GRUB_UTIL_FD_STAT_IS_FUNCTIONAL
155 struct stat st;
157 if (stat (os_dev, &st) < 0)
159 const char *errstr = strerror (errno);
160 grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot stat `%s': %s"),
161 os_dev, errstr);
162 grub_util_info (_("cannot stat `%s': %s"), os_dev, errstr);
163 return 0;
166 *is_part = 0;
168 if (grub_util_device_is_mapped_stat (&st))
169 return grub_util_devmapper_part_to_disk (&st, is_part, os_dev);
171 *is_part = 0;
173 return grub_util_part_to_disk (os_dev, &st, is_part);
174 #else
175 *is_part = 0;
177 return grub_util_part_to_disk (os_dev, NULL, is_part);
178 #endif
181 static const char *
182 find_system_device (const char *os_dev)
184 char *os_disk;
185 const char *drive;
186 int is_part;
188 os_disk = convert_system_partition_to_system_disk (os_dev, &is_part);
189 if (! os_disk)
190 return NULL;
192 drive = grub_hostdisk_os_dev_to_grub_drive (os_disk, 0);
193 free (os_disk);
194 return drive;
197 static char *
198 make_device_name (const char *drive)
200 char *ret, *ptr;
201 const char *iptr;
203 ret = xmalloc (strlen (drive) * 2);
204 ptr = ret;
205 for (iptr = drive; *iptr; iptr++)
207 if (*iptr == ',' || *iptr == '\\')
208 *ptr++ = '\\';
209 *ptr++ = *iptr;
211 *ptr = 0;
213 return ret;
216 char *
217 grub_util_get_os_disk (const char *os_dev)
219 int is_part;
221 grub_util_info ("Looking for %s", os_dev);
223 return convert_system_partition_to_system_disk (os_dev, &is_part);
226 #if !defined(__APPLE__)
227 /* Context for grub_util_biosdisk_get_grub_dev. */
228 struct grub_util_biosdisk_get_grub_dev_ctx
230 char *partname;
231 grub_disk_addr_t start;
234 /* Helper for grub_util_biosdisk_get_grub_dev. */
235 static int
236 find_partition (grub_disk_t dsk __attribute__ ((unused)),
237 const grub_partition_t partition, void *data)
239 struct grub_util_biosdisk_get_grub_dev_ctx *ctx = data;
240 grub_disk_addr_t part_start = 0;
241 grub_util_info ("Partition %d starts from %" GRUB_HOST_PRIuLONG_LONG,
242 partition->number, (unsigned long long) partition->start);
244 part_start = grub_partition_get_start (partition);
246 if (ctx->start == part_start)
248 ctx->partname = grub_partition_get_name (partition);
249 return 1;
252 return 0;
254 #endif
256 char *
257 grub_util_biosdisk_get_grub_dev (const char *os_dev)
259 const char *drive;
260 char *sys_disk;
261 int is_part;
263 grub_util_info ("Looking for %s", os_dev);
265 sys_disk = convert_system_partition_to_system_disk (os_dev, &is_part);
267 if (!sys_disk)
268 return 0;
270 drive = grub_hostdisk_os_dev_to_grub_drive (sys_disk, 1);
272 grub_util_info ("%s is a parent of %s", sys_disk, os_dev);
273 if (!is_part)
275 free (sys_disk);
276 return make_device_name (drive);
278 free (sys_disk);
280 #if defined(__APPLE__)
281 /* Apple uses "/dev/r?disk[0-9]+(s[0-9]+)?". */
283 * Note: we do not use the new partition naming scheme as dos_part does not
284 * necessarily correspond to an msdos partition.
287 const char *p;
288 char *dri, *ret;
289 int part;
290 int disk = (grub_memcmp (os_dev, "/dev/disk", sizeof ("/dev/disk") - 1)
291 == 0);
292 int rdisk = (grub_memcmp (os_dev, "/dev/rdisk", sizeof ("/dev/rdisk") - 1)
293 == 0);
295 dri = make_device_name (drive);
297 if (!disk && !rdisk)
298 return dri;
300 p = os_dev + sizeof ("/dev/disk") + rdisk - 1;
301 while (*p >= '0' && *p <= '9')
302 p++;
303 if (*p != 's')
304 return dri;
305 p++;
307 part = strtol (p, NULL, 10);
308 if (part == 0)
309 return dri;
311 ret = xasprintf ("%s,%d", dri, part);
312 free (dri);
314 return ret;
317 #else
319 /* Linux counts partitions uniformly, whether a BSD partition or a DOS
320 partition, so mapping them to GRUB devices is not trivial.
321 Here, get the start sector of a partition by HDIO_GETGEO, and
322 compare it with each partition GRUB recognizes.
324 Cygwin /dev/sdXN emulation uses Windows partition mapping. It
325 does not count the extended partition and missing primary
326 partitions. Use same method as on Linux here.
328 For NetBSD and FreeBSD, proceed as for Linux, except that the start
329 sector is obtained from the disk label. */
331 char *name;
332 grub_disk_t disk;
333 struct grub_util_biosdisk_get_grub_dev_ctx ctx;
335 name = make_device_name (drive);
337 ctx.start = grub_util_find_partition_start (os_dev);
338 if (grub_errno != GRUB_ERR_NONE)
340 free (name);
341 return 0;
344 #if defined(__GNU__)
345 /* Some versions of Hurd use badly glued Linux code to handle partitions
346 resulting in partitions being promoted to disks. */
347 /* GNU uses "/dev/[hs]d[0-9]+(s[0-9]+[a-z]?)?". */
349 * Note: we do not use the new partition naming scheme as dos_part does not
350 * necessarily correspond to an msdos partition.
352 if (ctx.start == (grub_disk_addr_t) -1)
354 char *p;
355 char *dri;
357 dri = make_device_name (drive);
359 p = strrchr (os_dev + sizeof ("/dev/hd") - 1, 's');
360 if (p)
362 long int n;
363 char *q;
365 p++;
366 n = strtol (p, &q, 10);
367 if (p != q && n > 0 && n != GRUB_LONG_MAX)
369 char *t;
370 t = dri;
371 if (*q >= 'a' && *q <= 'g')
372 dri = xasprintf ("%s,%ld,%d", t, n, *q - 'a' + 1);
373 else
374 dri = xasprintf ("%s,%ld", t, n);
375 free (t);
379 return dri;
381 #endif
383 grub_util_info ("%s starts from %" GRUB_HOST_PRIuLONG_LONG,
384 os_dev, (unsigned long long) ctx.start);
386 if (ctx.start == 0 && !is_part)
387 return name;
389 grub_util_info ("opening the device %s", name);
390 disk = grub_disk_open (name);
391 free (name);
393 if (! disk)
395 /* We already know that the partition exists. Given that we already
396 checked the device map above, we can only get
397 GRUB_ERR_UNKNOWN_DEVICE at this point if the disk does not exist.
398 This can happen on Xen, where disk images in the host can be
399 assigned to devices that have partition-like names in the guest
400 but are really more like disks. */
401 if (grub_errno == GRUB_ERR_UNKNOWN_DEVICE)
403 char *canon;
404 grub_util_warn
405 (_("disk does not exist, so falling back to partition device %s"),
406 os_dev);
407 grub_errno = GRUB_ERR_NONE;
409 canon = canonicalize_file_name (os_dev);
410 drive = grub_hostdisk_os_dev_to_grub_drive (canon ? : os_dev, 1);
411 if (canon)
412 free (canon);
413 return make_device_name (drive);
415 else
416 return 0;
419 name = grub_util_get_ldm (disk, ctx.start);
420 if (name)
422 grub_disk_close (disk);
423 return name;
426 ctx.partname = NULL;
428 grub_partition_iterate (disk, find_partition, &ctx);
429 if (grub_errno != GRUB_ERR_NONE)
431 grub_disk_close (disk);
432 return 0;
435 if (ctx.partname == NULL)
437 grub_disk_close (disk);
438 grub_util_info ("cannot find the partition of `%s'", os_dev);
439 grub_error (GRUB_ERR_BAD_DEVICE,
440 "cannot find the partition of `%s'", os_dev);
441 return 0;
444 name = grub_xasprintf ("%s,%s", disk->name, ctx.partname);
445 free (ctx.partname);
446 grub_disk_close (disk);
447 return name;
450 #endif
454 grub_util_biosdisk_is_present (const char *os_dev)
456 int ret = (find_system_device (os_dev) != NULL);
457 grub_util_info ((ret ? "%s is present" : "%s is not present"),
458 os_dev);
459 return ret;
462 #ifdef HAVE_LIBZFS
463 static libzfs_handle_t *__libzfs_handle;
465 static void
466 fini_libzfs (void)
468 libzfs_fini (__libzfs_handle);
471 libzfs_handle_t *
472 grub_get_libzfs_handle (void)
474 if (! __libzfs_handle)
476 __libzfs_handle = libzfs_init ();
478 if (__libzfs_handle)
479 atexit (fini_libzfs);
482 return __libzfs_handle;
484 #endif /* HAVE_LIBZFS */