]>
Commit | Line | Data |
---|---|---|
7cd0df84 VS |
1 | /* |
2 | * GRUB -- GRand Unified Bootloader | |
3 | * Copyright (C) 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 <grub/types.h> | |
20 | #include <grub/misc.h> | |
21 | #include <grub/mm.h> | |
22 | #include <grub/err.h> | |
23 | #include <grub/dl.h> | |
24 | #include <grub/command.h> | |
25 | #include <grub/i18n.h> | |
26 | #include <grub/device.h> | |
27 | #include <grub/mm.h> | |
28 | #include <grub/fs.h> | |
29 | #include <grub/env.h> | |
30 | #include <grub/file.h> | |
31 | ||
32 | GRUB_MOD_LICENSE ("GPLv3+"); | |
33 | ||
ef9d8cd5 VS |
34 | static const char *modnames_def[] = { |
35 | /* FIXME: autogenerate this. */ | |
36 | #if defined (__i386__) || defined (__x86_64__) || defined (GRUB_MACHINE_MIPS_LOONGSON) | |
37 | "pata", "ahci", "usbms", "ohci", "uhci", "ehci" | |
38 | #elif defined (GRUB_MACHINE_MIPS_QEMU_MIPS) | |
39 | "pata" | |
40 | #else | |
41 | #error "Fill this" | |
42 | #endif | |
43 | }; | |
7cd0df84 VS |
44 | |
45 | static grub_err_t | |
ef9d8cd5 | 46 | get_uuid (const char *name, char **uuid, int getnative) |
7cd0df84 VS |
47 | { |
48 | grub_device_t dev; | |
49 | grub_fs_t fs = 0; | |
50 | ||
ef9d8cd5 VS |
51 | *uuid = 0; |
52 | ||
7cd0df84 VS |
53 | dev = grub_device_open (name); |
54 | if (!dev) | |
55 | return grub_errno; | |
ef9d8cd5 VS |
56 | |
57 | if (!dev->disk) | |
58 | { | |
59 | grub_dprintf ("nativedisk", "Skipping non-disk\n"); | |
bd50aa32 | 60 | grub_device_close (dev); |
ef9d8cd5 VS |
61 | return 0; |
62 | } | |
63 | ||
64 | switch (dev->disk->dev->id) | |
65 | { | |
66 | /* Firmware disks. */ | |
67 | case GRUB_DISK_DEVICE_BIOSDISK_ID: | |
68 | case GRUB_DISK_DEVICE_OFDISK_ID: | |
3434ddec | 69 | case GRUB_DISK_DEVICE_OBDISK_ID: |
ef9d8cd5 VS |
70 | case GRUB_DISK_DEVICE_EFIDISK_ID: |
71 | case GRUB_DISK_DEVICE_NAND_ID: | |
72 | case GRUB_DISK_DEVICE_ARCDISK_ID: | |
73 | case GRUB_DISK_DEVICE_HOSTDISK_ID: | |
d65be02b | 74 | case GRUB_DISK_DEVICE_UBOOTDISK_ID: |
ef9d8cd5 VS |
75 | break; |
76 | ||
77 | /* Native disks. */ | |
78 | case GRUB_DISK_DEVICE_ATA_ID: | |
79 | case GRUB_DISK_DEVICE_SCSI_ID: | |
9612ebc0 | 80 | case GRUB_DISK_DEVICE_XEN: |
ef9d8cd5 VS |
81 | if (getnative) |
82 | break; | |
4bd4a887 | 83 | /* FALLTHROUGH */ |
ef9d8cd5 VS |
84 | |
85 | /* Virtual disks. */ | |
5027af38 | 86 | /* GRUB dynamically generated files. */ |
ef9d8cd5 | 87 | case GRUB_DISK_DEVICE_PROCFS_ID: |
5027af38 | 88 | /* To access through host OS routines (grub-emu only). */ |
ef9d8cd5 | 89 | case GRUB_DISK_DEVICE_HOST_ID: |
5027af38 VS |
90 | /* To access coreboot roms. */ |
91 | case GRUB_DISK_DEVICE_CBFSDISK_ID: | |
ef9d8cd5 VS |
92 | /* GRUB-only memdisk. Can't match any of firmware devices. */ |
93 | case GRUB_DISK_DEVICE_MEMDISK_ID: | |
94 | grub_dprintf ("nativedisk", "Skipping native disk %s\n", | |
95 | dev->disk->name); | |
bd50aa32 | 96 | grub_device_close (dev); |
ef9d8cd5 VS |
97 | return 0; |
98 | ||
99 | /* FIXME: those probably need special handling. */ | |
100 | case GRUB_DISK_DEVICE_LOOPBACK_ID: | |
101 | case GRUB_DISK_DEVICE_DISKFILTER_ID: | |
102 | case GRUB_DISK_DEVICE_CRYPTODISK_ID: | |
103 | break; | |
104 | } | |
7cd0df84 VS |
105 | if (dev) |
106 | fs = grub_fs_probe (dev); | |
107 | if (!fs) | |
108 | { | |
109 | grub_device_close (dev); | |
110 | return grub_errno; | |
111 | } | |
ad4bfeec | 112 | if (!fs->fs_uuid || fs->fs_uuid (dev, uuid) || !*uuid) |
7cd0df84 VS |
113 | { |
114 | grub_device_close (dev); | |
115 | ||
116 | if (!grub_errno) | |
117 | grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, | |
118 | N_("%s does not support UUIDs"), fs->name); | |
119 | ||
120 | return grub_errno; | |
121 | } | |
122 | grub_device_close (dev); | |
123 | return GRUB_ERR_NONE; | |
124 | } | |
125 | ||
126 | struct search_ctx | |
127 | { | |
128 | char *root_uuid; | |
129 | char *prefix_uuid; | |
130 | const char *prefix_path; | |
131 | int prefix_found, root_found; | |
132 | }; | |
133 | ||
134 | static int | |
135 | iterate_device (const char *name, void *data) | |
136 | { | |
137 | struct search_ctx *ctx = data; | |
138 | char *cur_uuid; | |
139 | ||
ef9d8cd5 | 140 | if (get_uuid (name, &cur_uuid, 1)) |
7cd0df84 | 141 | { |
adb7d667 VS |
142 | if (grub_errno == GRUB_ERR_UNKNOWN_FS) |
143 | grub_errno = 0; | |
7cd0df84 VS |
144 | grub_print_error (); |
145 | return 0; | |
146 | } | |
ef9d8cd5 VS |
147 | |
148 | grub_dprintf ("nativedisk", "checking %s: %s\n", name, | |
149 | cur_uuid); | |
150 | if (ctx->prefix_uuid && grub_strcasecmp (cur_uuid, ctx->prefix_uuid) == 0) | |
7cd0df84 VS |
151 | { |
152 | char *prefix; | |
153 | prefix = grub_xasprintf ("(%s)/%s", name, ctx->prefix_path); | |
154 | grub_env_set ("prefix", prefix); | |
155 | grub_free (prefix); | |
156 | ctx->prefix_found = 1; | |
157 | } | |
ef9d8cd5 | 158 | if (ctx->root_uuid && grub_strcasecmp (cur_uuid, ctx->root_uuid) == 0) |
7cd0df84 VS |
159 | { |
160 | grub_env_set ("root", name); | |
161 | ctx->root_found = 1; | |
162 | } | |
163 | return ctx->prefix_found && ctx->root_found; | |
164 | } | |
165 | ||
166 | static grub_err_t | |
167 | grub_cmd_nativedisk (grub_command_t cmd __attribute__ ((unused)), | |
168 | int argc, char **args_in) | |
169 | { | |
170 | char *uuid_root = 0, *uuid_prefix, *prefdev = 0; | |
171 | const char *prefix = 0; | |
172 | const char *path_prefix = 0; | |
173 | int mods_loaded = 0; | |
174 | grub_dl_t *mods; | |
7cd0df84 | 175 | const char **args; |
7cd0df84 VS |
176 | int i; |
177 | ||
178 | if (argc == 0) | |
179 | { | |
180 | argc = ARRAY_SIZE (modnames_def); | |
181 | args = modnames_def; | |
182 | } | |
183 | else | |
184 | args = (const char **) args_in; | |
185 | ||
186 | prefix = grub_env_get ("prefix"); | |
187 | ||
188 | if (! prefix) | |
189 | return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("variable `%s' isn't set"), "prefix"); | |
190 | ||
191 | if (prefix) | |
192 | path_prefix = (prefix[0] == '(') ? grub_strchr (prefix, ')') : NULL; | |
193 | if (path_prefix) | |
194 | path_prefix++; | |
195 | else | |
196 | path_prefix = prefix; | |
197 | ||
198 | mods = grub_malloc (argc * sizeof (mods[0])); | |
199 | if (!mods) | |
200 | return grub_errno; | |
201 | ||
ef9d8cd5 | 202 | if (get_uuid (NULL, &uuid_root, 0)) |
1bff60e5 AB |
203 | { |
204 | grub_free (mods); | |
205 | return grub_errno; | |
206 | } | |
7cd0df84 VS |
207 | |
208 | prefdev = grub_file_get_device_name (prefix); | |
209 | if (grub_errno) | |
210 | { | |
211 | grub_print_error (); | |
212 | prefdev = 0; | |
213 | } | |
214 | ||
ef9d8cd5 | 215 | if (get_uuid (prefdev, &uuid_prefix, 0)) |
7cd0df84 VS |
216 | { |
217 | grub_free (uuid_root); | |
1bff60e5 AB |
218 | grub_free (prefdev); |
219 | grub_free (mods); | |
7cd0df84 VS |
220 | return grub_errno; |
221 | } | |
222 | ||
ef9d8cd5 VS |
223 | grub_dprintf ("nativedisk", "uuid_prefix = %s, uuid_root = %s\n", |
224 | uuid_prefix, uuid_root); | |
225 | ||
7cd0df84 VS |
226 | for (mods_loaded = 0; mods_loaded < argc; mods_loaded++) |
227 | { | |
228 | char *filename; | |
229 | grub_dl_t mod; | |
230 | grub_file_t file = NULL; | |
231 | grub_ssize_t size; | |
232 | void *core = 0; | |
233 | ||
234 | mod = grub_dl_get (args[mods_loaded]); | |
235 | if (mod) | |
236 | { | |
237 | mods[mods_loaded] = 0; | |
238 | continue; | |
239 | } | |
240 | ||
241 | filename = grub_xasprintf ("%s/" GRUB_TARGET_CPU "-" GRUB_PLATFORM "/%s.mod", | |
242 | prefix, args[mods_loaded]); | |
243 | if (! filename) | |
244 | goto fail; | |
245 | ||
ca0a4f68 VS |
246 | file = grub_file_open (filename, |
247 | GRUB_FILE_TYPE_GRUB_MODULE); | |
7cd0df84 VS |
248 | grub_free (filename); |
249 | if (! file) | |
250 | goto fail; | |
251 | ||
252 | size = grub_file_size (file); | |
253 | core = grub_malloc (size); | |
254 | if (! core) | |
255 | { | |
256 | grub_file_close (file); | |
257 | goto fail; | |
258 | } | |
259 | ||
260 | if (grub_file_read (file, core, size) != (grub_ssize_t) size) | |
261 | { | |
262 | grub_file_close (file); | |
263 | grub_free (core); | |
264 | goto fail; | |
265 | } | |
266 | ||
267 | grub_file_close (file); | |
268 | ||
269 | mods[mods_loaded] = grub_dl_load_core_noinit (core, size); | |
270 | if (! mods[mods_loaded]) | |
271 | goto fail; | |
272 | } | |
273 | ||
274 | for (i = 0; i < argc; i++) | |
275 | if (mods[i]) | |
276 | grub_dl_init (mods[i]); | |
277 | ||
ef9d8cd5 VS |
278 | if (uuid_prefix || uuid_root) |
279 | { | |
280 | struct search_ctx ctx; | |
281 | grub_fs_autoload_hook_t saved_autoload; | |
7cd0df84 | 282 | |
ef9d8cd5 VS |
283 | /* No need to autoload FS since obviously we already have the necessary fs modules. */ |
284 | saved_autoload = grub_fs_autoload_hook; | |
285 | grub_fs_autoload_hook = 0; | |
7cd0df84 | 286 | |
ef9d8cd5 VS |
287 | ctx.root_uuid = uuid_root; |
288 | ctx.prefix_uuid = uuid_prefix; | |
289 | ctx.prefix_path = path_prefix; | |
290 | ctx.prefix_found = !uuid_prefix; | |
291 | ctx.root_found = !uuid_root; | |
7cd0df84 | 292 | |
ef9d8cd5 VS |
293 | /* FIXME: try to guess the correct values. */ |
294 | grub_device_iterate (iterate_device, &ctx); | |
7cd0df84 | 295 | |
ef9d8cd5 VS |
296 | grub_fs_autoload_hook = saved_autoload; |
297 | } | |
7cd0df84 VS |
298 | grub_free (uuid_root); |
299 | grub_free (uuid_prefix); | |
1bff60e5 AB |
300 | grub_free (prefdev); |
301 | grub_free (mods); | |
7cd0df84 VS |
302 | |
303 | return GRUB_ERR_NONE; | |
304 | ||
305 | fail: | |
306 | grub_free (uuid_root); | |
307 | grub_free (uuid_prefix); | |
1bff60e5 | 308 | grub_free (prefdev); |
7cd0df84 VS |
309 | |
310 | for (i = 0; i < mods_loaded; i++) | |
311 | if (mods[i]) | |
312 | { | |
313 | mods[i]->fini = 0; | |
314 | grub_dl_unload (mods[i]); | |
315 | } | |
1bff60e5 AB |
316 | grub_free (mods); |
317 | ||
7cd0df84 VS |
318 | return grub_errno; |
319 | } | |
320 | ||
321 | static grub_command_t cmd; | |
322 | ||
323 | GRUB_MOD_INIT(nativedisk) | |
324 | { | |
d22840ec | 325 | cmd = grub_register_command ("nativedisk", grub_cmd_nativedisk, N_("[MODULE1 MODULE2 ...]"), |
7cd0df84 VS |
326 | N_("Switch to native disk drivers. If no modules are specified default set (pata,ahci,usbms,ohci,uhci,ehci) is used")); |
327 | } | |
328 | ||
329 | GRUB_MOD_FINI(nativedisk) | |
330 | { | |
331 | grub_unregister_command (cmd); | |
332 | } |