1 /* getroot.c - Get root device */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 1999,2000,2001,2002,2003,2006,2007,2008 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/>.
25 #include <grub/util/misc.h>
26 #include <grub/util/biosdisk.h>
27 #include <grub/util/getroot.h>
30 strip_extra_slashes (char *dir
)
34 while ((p
= strchr (p
, '/')) != 0)
38 memmove (p
, p
+ 1, strlen (p
));
41 else if (p
[1] == '\0')
57 path
= xmalloc (size
);
58 while (! getcwd (path
, size
))
61 path
= xrealloc (path
, size
);
68 grub_get_prefix (const char *dir
)
71 char *abs_dir
, *prev_dir
;
73 struct stat st
, prev_st
;
75 /* Save the current directory. */
76 saved_cwd
= xgetcwd ();
79 grub_util_error ("Cannot change directory to `%s'", dir
);
82 strip_extra_slashes (abs_dir
);
83 prev_dir
= xstrdup (abs_dir
);
85 if (stat (".", &prev_st
) < 0)
86 grub_util_error ("Cannot stat `%s'", dir
);
88 if (! S_ISDIR (prev_st
.st_mode
))
89 grub_util_error ("`%s' is not a directory", dir
);
94 grub_util_error ("Cannot change directory to the parent");
96 if (stat (".", &st
) < 0)
97 grub_util_error ("Cannot stat current directory");
99 if (! S_ISDIR (st
.st_mode
))
100 grub_util_error ("Current directory is not a directory???");
102 if (prev_st
.st_dev
!= st
.st_dev
|| prev_st
.st_ino
== st
.st_ino
)
106 prev_dir
= xgetcwd ();
110 strip_extra_slashes (prev_dir
);
111 prefix
= xmalloc (strlen (abs_dir
) - strlen (prev_dir
) + 2);
113 strcpy (prefix
+ 1, abs_dir
+ strlen (prev_dir
));
114 strip_extra_slashes (prefix
);
116 if (chdir (saved_cwd
) < 0)
117 grub_util_error ("Cannot change directory to `%s'", dir
);
123 grub_util_info ("prefix = %s", prefix
);
128 find_root_device (const char *dir
, dev_t dev
)
138 saved_cwd
= xgetcwd ();
140 grub_util_info ("changing current directory to %s", dir
);
148 while ((ent
= readdir (dp
)) != 0)
152 if (strcmp (ent
->d_name
, ".") == 0 || strcmp (ent
->d_name
, "..") == 0)
155 if (lstat (ent
->d_name
, &st
) < 0)
156 /* Ignore any error. */
159 if (S_ISLNK (st
.st_mode
))
160 /* Don't follow symbolic links. */
163 if (S_ISDIR (st
.st_mode
) && ent
->d_name
[0] != '.')
165 /* Find it recursively, but avoid dotdirs (like ".static") since they
166 could contain duplicates, which would later break the
167 pathname-based check */
170 res
= find_root_device (ent
->d_name
, dev
);
174 if (chdir (saved_cwd
) < 0)
175 grub_util_error ("Cannot restore the original directory");
183 if (S_ISBLK (st
.st_mode
) && st
.st_rdev
== dev
)
190 res
= xmalloc (strlen (cwd
) + strlen (ent
->d_name
) + 2);
191 sprintf (res
, "%s/%s", cwd
, ent
->d_name
);
192 strip_extra_slashes (res
);
195 /* /dev/root is not a real block device keep looking, takes care
196 of situation where root filesystem is on the same partition as
199 if (strcmp(res
, "/dev/root") == 0)
202 if (chdir (saved_cwd
) < 0)
203 grub_util_error ("Cannot restore the original directory");
211 if (chdir (saved_cwd
) < 0)
212 grub_util_error ("Cannot restore the original directory");
220 grub_guess_root_device (const char *dir
)
225 if (stat (dir
, &st
) < 0)
226 grub_util_error ("Cannot stat `%s'", dir
);
229 /* We first try to find the device in the /dev/mapper directory. If
230 we don't do this, we get useless device names like /dev/dm-0 for
232 os_dev
= find_root_device ("/dev/mapper", st
.st_dev
);
234 /* The same applies to /dev/evms directory (for EVMS volumes). */
236 os_dev
= find_root_device ("/dev/evms", st
.st_dev
);
241 /* This might be truly slow, but is there any better way? */
242 os_dev
= find_root_device ("/dev", st
.st_dev
);
249 grub_util_get_dev_abstraction (const char *os_dev
)
252 if (!strncmp (os_dev
, "/dev/mapper/", 12))
253 return GRUB_DEV_ABSTRACTION_LVM
;
255 /* Check for RAID. */
256 if (!strncmp (os_dev
, "/dev/md", 7))
257 return GRUB_DEV_ABSTRACTION_RAID
;
259 /* No abstraction found. */
260 return GRUB_DEV_ABSTRACTION_NONE
;
264 grub_util_get_grub_dev (const char *os_dev
)
268 switch (grub_util_get_dev_abstraction (os_dev
))
270 case GRUB_DEV_ABSTRACTION_LVM
:
271 grub_dev
= xmalloc (strlen (os_dev
) - 12 + 1);
273 strcpy (grub_dev
, os_dev
+ 12);
277 case GRUB_DEV_ABSTRACTION_RAID
:
278 grub_dev
= xmalloc (20);
280 if (os_dev
[7] == '_' && os_dev
[8] == 'd')
284 /* This a partitionable RAID device of the form /dev/md_dNNpMM. */
292 while (*p
>= '0' && *p
<= '9')
307 while (*p
>= '0' && *p
<= '9')
317 grub_util_error ("Unknown kind of RAID device `%s'", os_dev
);
319 else if (os_dev
[7] >= '0' && os_dev
[7] <= '9')
321 memcpy (grub_dev
, os_dev
+ 5, 7);
325 grub_util_error ("Unknown kind of RAID device `%s'", os_dev
);
329 default: /* GRUB_DEV_ABSTRACTION_NONE */
330 grub_dev
= grub_util_biosdisk_get_grub_dev (os_dev
);
337 grub_util_check_block_device (const char *blk_dev
)
341 if (stat (blk_dev
, &st
) < 0)
342 grub_util_error ("Cannot stat `%s'", blk_dev
);
344 if (S_ISBLK (st
.st_mode
))