]> git.proxmox.com Git - grub2.git/blob - grub-core/osdep/devmapper/getroot.c
Import grub2_2.02+dfsg1.orig.tar.xz
[grub2.git] / grub-core / osdep / devmapper / getroot.c
1 /*
2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 1999,2000,2001,2002,2003,2006,2007,2008,2009,2010,2011,2012,2013 Free Software Foundation, Inc.
4 *
5 * GRUB is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * GRUB is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <config-util.h>
20 #include <config.h>
21
22 #include <grub/emu/getroot.h>
23 #include <grub/mm.h>
24
25 #ifdef HAVE_DEVICE_MAPPER
26
27 #include <sys/stat.h>
28 #include <sys/types.h>
29 #include <assert.h>
30 #include <fcntl.h>
31 #include <unistd.h>
32 #include <string.h>
33 #include <dirent.h>
34 #include <errno.h>
35 #include <error.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <stdint.h>
39 #ifdef HAVE_LIMITS_H
40 #include <limits.h>
41 #endif
42
43 #if defined(MAJOR_IN_MKDEV)
44 #include <sys/mkdev.h>
45 #elif defined(MAJOR_IN_SYSMACROS)
46 #include <sys/sysmacros.h>
47 #endif
48
49 #include <libdevmapper.h>
50
51 #include <grub/types.h>
52 #include <grub/util/misc.h>
53
54 #include <grub/mm.h>
55 #include <grub/misc.h>
56 #include <grub/emu/misc.h>
57 #include <grub/emu/hostdisk.h>
58
59 static int
60 grub_util_open_dm (const char *os_dev, struct dm_tree **tree,
61 struct dm_tree_node **node)
62 {
63 uint32_t maj, min;
64 struct stat st;
65
66 *node = NULL;
67 *tree = NULL;
68
69 if (stat (os_dev, &st) < 0)
70 return 0;
71
72 maj = major (st.st_rdev);
73 min = minor (st.st_rdev);
74
75 if (!dm_is_dm_major (maj))
76 return 0;
77
78 *tree = dm_tree_create ();
79 if (! *tree)
80 {
81 grub_puts_ (N_("Failed to create `device-mapper' tree"));
82 grub_dprintf ("hostdisk", "dm_tree_create failed\n");
83 return 0;
84 }
85
86 if (! dm_tree_add_dev (*tree, maj, min))
87 {
88 grub_dprintf ("hostdisk", "dm_tree_add_dev failed\n");
89 dm_tree_free (*tree);
90 *tree = NULL;
91 return 0;
92 }
93
94 *node = dm_tree_find_node (*tree, maj, min);
95 if (! *node)
96 {
97 grub_dprintf ("hostdisk", "dm_tree_find_node failed\n");
98 dm_tree_free (*tree);
99 *tree = NULL;
100 return 0;
101 }
102 return 1;
103 }
104
105 static char *
106 get_dm_uuid (const char *os_dev)
107 {
108 struct dm_tree *tree;
109 struct dm_tree_node *node;
110 const char *node_uuid;
111 char *ret;
112
113 if (!grub_util_open_dm (os_dev, &tree, &node))
114 return NULL;
115
116 node_uuid = dm_tree_node_get_uuid (node);
117 if (! node_uuid)
118 {
119 grub_dprintf ("hostdisk", "%s has no DM uuid\n", os_dev);
120 dm_tree_free (tree);
121 return NULL;
122 }
123
124 ret = grub_strdup (node_uuid);
125
126 dm_tree_free (tree);
127
128 return ret;
129 }
130
131 enum grub_dev_abstraction_types
132 grub_util_get_dm_abstraction (const char *os_dev)
133 {
134 char *uuid;
135
136 uuid = get_dm_uuid (os_dev);
137
138 if (uuid == NULL)
139 return GRUB_DEV_ABSTRACTION_NONE;
140
141 if (strncmp (uuid, "LVM-", 4) == 0)
142 {
143 grub_free (uuid);
144 return GRUB_DEV_ABSTRACTION_LVM;
145 }
146 if (strncmp (uuid, "CRYPT-LUKS1-", 12) == 0)
147 {
148 grub_free (uuid);
149 return GRUB_DEV_ABSTRACTION_LUKS;
150 }
151
152 grub_free (uuid);
153 return GRUB_DEV_ABSTRACTION_NONE;
154 }
155
156 void
157 grub_util_pull_devmapper (const char *os_dev)
158 {
159 struct dm_tree *tree;
160 struct dm_tree_node *node;
161 struct dm_tree_node *child;
162 void *handle = NULL;
163 char *lastsubdev = NULL;
164 char *uuid;
165
166 uuid = get_dm_uuid (os_dev);
167
168 if (!grub_util_open_dm (os_dev, &tree, &node))
169 {
170 grub_free (uuid);
171 return;
172 }
173
174 while ((child = dm_tree_next_child (&handle, node, 0)))
175 {
176 const struct dm_info *dm = dm_tree_node_get_info (child);
177 char *subdev;
178 if (!dm)
179 continue;
180 subdev = grub_find_device ("/dev", makedev (dm->major, dm->minor));
181 if (subdev)
182 {
183 lastsubdev = subdev;
184 grub_util_pull_device (subdev);
185 }
186 }
187 if (uuid && strncmp (uuid, "CRYPT-LUKS1-", sizeof ("CRYPT-LUKS1-") - 1) == 0
188 && lastsubdev)
189 {
190 char *grdev = grub_util_get_grub_dev (lastsubdev);
191 dm_tree_free (tree);
192 if (grdev)
193 {
194 grub_err_t err;
195 err = grub_cryptodisk_cheat_mount (grdev, os_dev);
196 if (err)
197 grub_util_error (_("can't mount encrypted volume `%s': %s"),
198 lastsubdev, grub_errmsg);
199 }
200 grub_free (grdev);
201 }
202 else
203 dm_tree_free (tree);
204 grub_free (uuid);
205 }
206
207 char *
208 grub_util_devmapper_part_to_disk (struct stat *st,
209 int *is_part, const char *path)
210 {
211 int major, minor;
212
213 if (grub_util_get_dm_node_linear_info (st->st_rdev,
214 &major, &minor, 0))
215 {
216 *is_part = 1;
217 return grub_find_device ("/dev", makedev (major, minor));
218 }
219 *is_part = 0;
220 return xstrdup (path);
221 }
222
223 char *
224 grub_util_get_devmapper_grub_dev (const char *os_dev)
225 {
226 char *uuid, *optr;
227 char *grub_dev;
228
229 uuid = get_dm_uuid (os_dev);
230 if (!uuid)
231 return NULL;
232
233 switch (grub_util_get_dev_abstraction (os_dev))
234 {
235 case GRUB_DEV_ABSTRACTION_LVM:
236 {
237 unsigned i;
238 int dashes[] = { 0, 6, 10, 14, 18, 22, 26, 32, 38, 42, 46, 50, 54, 58};
239
240 grub_dev = xmalloc (grub_strlen (uuid) + 40);
241 optr = grub_stpcpy (grub_dev, "lvmid/");
242 for (i = 0; i < ARRAY_SIZE (dashes) - 1; i++)
243 {
244 memcpy (optr, uuid + sizeof ("LVM-") - 1 + dashes[i],
245 dashes[i+1] - dashes[i]);
246 optr += dashes[i+1] - dashes[i];
247 *optr++ = '-';
248 }
249 optr = stpcpy (optr, uuid + sizeof ("LVM-") - 1 + dashes[i]);
250 *optr = '\0';
251 grub_dev[sizeof("lvmid/xxxxxx-xxxx-xxxx-xxxx-xxxx-xxxx-xxxxxx") - 1]
252 = '/';
253 free (uuid);
254 return grub_dev;
255 }
256
257 case GRUB_DEV_ABSTRACTION_LUKS:
258 {
259 char *dash;
260
261 dash = grub_strchr (uuid + sizeof ("CRYPT-LUKS1-") - 1, '-');
262 if (dash)
263 *dash = 0;
264 grub_dev = grub_xasprintf ("cryptouuid/%s",
265 uuid + sizeof ("CRYPT-LUKS1-") - 1);
266 grub_free (uuid);
267 return grub_dev;
268 }
269
270 default:
271 grub_free (uuid);
272 return NULL;
273 }
274 }
275
276 char *
277 grub_util_get_vg_uuid (const char *os_dev)
278 {
279 char *uuid, *vgid;
280 int dashes[] = { 0, 6, 10, 14, 18, 22, 26, 32};
281 unsigned i;
282 char *optr;
283
284 uuid = get_dm_uuid (os_dev);
285 if (!uuid)
286 return NULL;
287
288 vgid = xmalloc (grub_strlen (uuid));
289 optr = vgid;
290 for (i = 0; i < ARRAY_SIZE (dashes) - 1; i++)
291 {
292 memcpy (optr, uuid + sizeof ("LVM-") - 1 + dashes[i],
293 dashes[i+1] - dashes[i]);
294 optr += dashes[i+1] - dashes[i];
295 *optr++ = '-';
296 }
297 optr--;
298 *optr = '\0';
299 grub_free (uuid);
300 return vgid;
301 }
302
303 void
304 grub_util_devmapper_cleanup (void)
305 {
306 dm_lib_release ();
307 }
308
309 #else
310 void
311 grub_util_pull_devmapper (const char *os_dev __attribute__ ((unused)))
312 {
313 return;
314 }
315
316 void
317 grub_util_devmapper_cleanup (void)
318 {
319 }
320
321 enum grub_dev_abstraction_types
322 grub_util_get_dm_abstraction (const char *os_dev __attribute__ ((unused)))
323 {
324 return GRUB_DEV_ABSTRACTION_NONE;
325 }
326
327 char *
328 grub_util_get_vg_uuid (const char *os_dev __attribute__ ((unused)))
329 {
330 return NULL;
331 }
332
333 char *
334 grub_util_devmapper_part_to_disk (struct stat *st __attribute__ ((unused)),
335 int *is_part __attribute__ ((unused)),
336 const char *os_dev __attribute__ ((unused)))
337 {
338 return NULL;
339 }
340
341 char *
342 grub_util_get_devmapper_grub_dev (const char *os_dev __attribute__ ((unused)))
343 {
344 return NULL;
345 }
346
347 #endif