void grub_util_pull_devmapper (const char *os_dev) { struct dm_tree *tree; struct dm_tree_node *node; struct dm_tree_node *child; void *handle = NULL; char *lastsubdev = NULL; char *uuid; uuid = get_dm_uuid (os_dev); if (!grub_util_open_dm (os_dev, &tree, &node)) { grub_free (uuid); return; } while ((child = dm_tree_next_child (&handle, node, 0))) { const struct dm_info *dm = dm_tree_node_get_info (child); char *subdev; if (!dm) continue; subdev = grub_find_device ("/dev", makedev (dm->major, dm->minor)); if (subdev) { lastsubdev = subdev; grub_util_pull_device (subdev); } } if (uuid && strncmp (uuid, "CRYPT-LUKS1-", sizeof ("CRYPT-LUKS1-") - 1) == 0 && lastsubdev) { char *grdev = grub_util_get_grub_dev (lastsubdev); dm_tree_free (tree); if (grdev) { grub_err_t err; err = grub_cryptodisk_cheat_mount (grdev, os_dev); if (err) grub_util_error (_("can't mount encrypted volume `%s': %s"), lastsubdev, grub_errmsg); } grub_free (grdev); } else dm_tree_free (tree); grub_free (uuid); }
char * grub_util_devmapper_part_to_disk (struct stat *st, int *is_part, const char *path) { int major, minor; if (grub_util_get_dm_node_linear_info (st->st_rdev, &major, &minor, 0)) { *is_part = 1; return grub_find_device ("/dev", makedev (major, minor)); } *is_part = 0; return xstrdup (path); }
char * grub_find_device (const char *dir, dev_t dev) { DIR *dp; char *saved_cwd; struct dirent *ent; if (! dir) dir = "/dev"; dp = opendir (dir); if (! dp) return 0; saved_cwd = xgetcwd (); grub_util_info ("changing current directory to %s", dir); if (chdir (dir) < 0) { free (saved_cwd); closedir (dp); return 0; } while ((ent = readdir (dp)) != 0) { struct stat st; /* Avoid: - dotfiles (like "/dev/.tmp.md0") since they could be duplicates. - dotdirs (like "/dev/.static") since they could contain duplicates. */ if (ent->d_name[0] == '.') continue; if (lstat (ent->d_name, &st) < 0) /* Ignore any error. */ continue; if (S_ISLNK (st.st_mode)) { #ifdef __linux__ if (strcmp (dir, "mapper") == 0 || strcmp (dir, "/dev/mapper") == 0) { /* Follow symbolic links under /dev/mapper/; the canonical name may be something like /dev/dm-0, but the names under /dev/mapper/ are more human-readable and so we prefer them if we can get them. */ if (stat (ent->d_name, &st) < 0) continue; } else #endif /* __linux__ */ /* Don't follow other symbolic links. */ continue; } if (S_ISDIR (st.st_mode)) { /* Find it recursively. */ char *res; res = grub_find_device (ent->d_name, dev); if (res) { if (chdir (saved_cwd) < 0) grub_util_error ("%s", _("cannot restore the original directory")); free (saved_cwd); closedir (dp); return res; } } #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) if (S_ISCHR (st.st_mode) && st.st_rdev == dev) #else if (S_ISBLK (st.st_mode) && st.st_rdev == dev) #endif { #ifdef __linux__ /* Skip device names like /dev/dm-0, which are short-hand aliases to more descriptive device names, e.g. those under /dev/mapper */ if (ent->d_name[0] == 'd' && ent->d_name[1] == 'm' && ent->d_name[2] == '-' && ent->d_name[3] >= '0' && ent->d_name[3] <= '9') continue; #endif /* Found! */ char *res; char *cwd; cwd = xgetcwd (); res = xmalloc (strlen (cwd) + strlen (ent->d_name) + 3); sprintf (res, #if defined(__NetBSD__) || defined(__OpenBSD__) /* Convert this block device to its character (raw) device. */ "%s/r%s", #else /* Keep the device name as it is. */ "%s/%s", #endif cwd, ent->d_name); strip_extra_slashes (res); free (cwd); /* /dev/root is not a real block device keep looking, takes care of situation where root filesystem is on the same partition as grub files */ if (strcmp(res, "/dev/root") == 0) { free (res); continue; } if (chdir (saved_cwd) < 0) grub_util_error ("%s", _("cannot restore the original directory")); free (saved_cwd); closedir (dp); return res; } } if (chdir (saved_cwd) < 0) grub_util_error ("%s", _("cannot restore the original directory")); free (saved_cwd); closedir (dp); return 0; }