make the linux-ppc packags be in synch with other platforms
[tangerine.git] / arch / common / boot / grub2 / util / getroot.c
blob5a9821883d723d8c73a5fc788a2d0954935e40a6
1 /* getroot.c - Get root device */
2 /*
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/>.
20 #include <sys/stat.h>
21 #include <unistd.h>
22 #include <string.h>
23 #include <dirent.h>
25 #include <grub/util/misc.h>
26 #include <grub/util/biosdisk.h>
27 #include <grub/util/getroot.h>
29 static void
30 strip_extra_slashes (char *dir)
32 char *p = dir;
34 while ((p = strchr (p, '/')) != 0)
36 if (p[1] == '/')
38 memmove (p, p + 1, strlen (p));
39 continue;
41 else if (p[1] == '\0')
43 p[0] = '\0';
44 break;
47 p++;
51 static char *
52 xgetcwd (void)
54 size_t size = 10;
55 char *path;
57 path = xmalloc (size);
58 while (! getcwd (path, size))
60 size <<= 1;
61 path = xrealloc (path, size);
64 return path;
67 char *
68 grub_get_prefix (const char *dir)
70 char *saved_cwd;
71 char *abs_dir, *prev_dir;
72 char *prefix;
73 struct stat st, prev_st;
75 /* Save the current directory. */
76 saved_cwd = xgetcwd ();
78 if (chdir (dir) < 0)
79 grub_util_error ("Cannot change directory to `%s'", dir);
81 abs_dir = xgetcwd ();
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);
91 while (1)
93 if (chdir ("..") < 0)
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)
103 break;
105 free (prev_dir);
106 prev_dir = xgetcwd ();
107 prev_st = st;
110 strip_extra_slashes (prev_dir);
111 prefix = xmalloc (strlen (abs_dir) - strlen (prev_dir) + 2);
112 prefix[0] = '/';
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);
119 free (saved_cwd);
120 free (abs_dir);
121 free (prev_dir);
123 grub_util_info ("prefix = %s", prefix);
124 return prefix;
127 static char *
128 find_root_device (const char *dir, dev_t dev)
130 DIR *dp;
131 char *saved_cwd;
132 struct dirent *ent;
134 dp = opendir (dir);
135 if (! dp)
136 return 0;
138 saved_cwd = xgetcwd ();
140 grub_util_info ("changing current directory to %s", dir);
141 if (chdir (dir) < 0)
143 free (saved_cwd);
144 closedir (dp);
145 return 0;
148 while ((ent = readdir (dp)) != 0)
150 struct stat st;
152 if (strcmp (ent->d_name, ".") == 0 || strcmp (ent->d_name, "..") == 0)
153 continue;
155 if (lstat (ent->d_name, &st) < 0)
156 /* Ignore any error. */
157 continue;
159 if (S_ISLNK (st.st_mode))
160 /* Don't follow symbolic links. */
161 continue;
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 */
168 char *res;
170 res = find_root_device (ent->d_name, dev);
172 if (res)
174 if (chdir (saved_cwd) < 0)
175 grub_util_error ("Cannot restore the original directory");
177 free (saved_cwd);
178 closedir (dp);
179 return res;
183 if (S_ISBLK (st.st_mode) && st.st_rdev == dev)
185 /* Found! */
186 char *res;
187 char *cwd;
189 cwd = xgetcwd ();
190 res = xmalloc (strlen (cwd) + strlen (ent->d_name) + 2);
191 sprintf (res, "%s/%s", cwd, ent->d_name);
192 strip_extra_slashes (res);
193 free (cwd);
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
197 grub files */
199 if (strcmp(res, "/dev/root") == 0)
200 continue;
202 if (chdir (saved_cwd) < 0)
203 grub_util_error ("Cannot restore the original directory");
205 free (saved_cwd);
206 closedir (dp);
207 return res;
211 if (chdir (saved_cwd) < 0)
212 grub_util_error ("Cannot restore the original directory");
214 free (saved_cwd);
215 closedir (dp);
216 return 0;
219 char *
220 grub_guess_root_device (const char *dir)
222 struct stat st;
223 char *os_dev;
225 if (stat (dir, &st) < 0)
226 grub_util_error ("Cannot stat `%s'", dir);
228 #ifdef __linux__
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
231 LVM. */
232 os_dev = find_root_device ("/dev/mapper", st.st_dev);
234 /* The same applies to /dev/evms directory (for EVMS volumes). */
235 if (! os_dev)
236 os_dev = find_root_device ("/dev/evms", st.st_dev);
238 if (! os_dev)
239 #endif
241 /* This might be truly slow, but is there any better way? */
242 os_dev = find_root_device ("/dev", st.st_dev);
245 return os_dev;
249 grub_util_get_dev_abstraction (const char *os_dev)
251 /* Check for LVM. */
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;
263 char *
264 grub_util_get_grub_dev (const char *os_dev)
266 char *grub_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);
275 break;
277 case GRUB_DEV_ABSTRACTION_RAID:
278 grub_dev = xmalloc (20);
280 if (os_dev[7] == '_' && os_dev[8] == 'd')
282 const char *p;
284 /* This a partitionable RAID device of the form /dev/md_dNNpMM. */
285 int i;
287 grub_dev[0] = 'm';
288 grub_dev[1] = 'd';
289 i = 2;
291 p = os_dev + 9;
292 while (*p >= '0' && *p <= '9')
294 grub_dev[i] = *p;
295 i++;
296 p++;
299 if (*p == '\0')
300 grub_dev[i] = '\0';
301 else if (*p == 'p')
303 p++;
304 grub_dev[i] = ',';
305 i++;
307 while (*p >= '0' && *p <= '9')
309 grub_dev[i] = *p;
310 i++;
311 p++;
314 grub_dev[i] = '\0';
316 else
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);
322 grub_dev[7] = '\0';
324 else
325 grub_util_error ("Unknown kind of RAID device `%s'", os_dev);
327 break;
329 default: /* GRUB_DEV_ABSTRACTION_NONE */
330 grub_dev = grub_util_biosdisk_get_grub_dev (os_dev);
333 return grub_dev;
336 const char *
337 grub_util_check_block_device (const char *blk_dev)
339 struct stat st;
341 if (stat (blk_dev, &st) < 0)
342 grub_util_error ("Cannot stat `%s'", blk_dev);
344 if (S_ISBLK (st.st_mode))
345 return (blk_dev);
346 else
347 return 0;