]>
Commit | Line | Data |
---|---|---|
6a161fa9 | 1 | /* |
4b13b216 | 2 | * GRUB -- GRand Unified Bootloader |
5a79f472 | 3 | * Copyright (C) 2002,2007 Free Software Foundation, Inc. |
6a161fa9 | 4 | * |
5a79f472 | 5 | * GRUB is free software: you can redistribute it and/or modify |
6a161fa9 | 6 | * it under the terms of the GNU General Public License as published by |
5a79f472 | 7 | * the Free Software Foundation, either version 3 of the License, or |
6a161fa9 | 8 | * (at your option) any later version. |
9 | * | |
5a79f472 | 10 | * GRUB is distributed in the hope that it will be useful, |
6a161fa9 | 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 | |
5a79f472 | 16 | * along with GRUB. If not, see <http://www.gnu.org/licenses/>. |
6a161fa9 | 17 | */ |
18 | ||
1d12cf29 YB |
19 | #include <config.h> |
20 | ||
6a161fa9 | 21 | #include <stdio.h> |
22 | #include <string.h> | |
23 | #include <stdlib.h> | |
24 | #include <ctype.h> | |
0ae70393 | 25 | #include <errno.h> |
6a161fa9 | 26 | |
8c411768 | 27 | #include <grub/emu/misc.h> |
88d51eff | 28 | #include <grub/misc.h> |
4b13b216 | 29 | #include <grub/util/misc.h> |
8c411768 | 30 | #include <grub/util/resolve.h> |
6e0632e2 | 31 | #include <grub/i18n.h> |
6a161fa9 | 32 | |
33 | /* Module. */ | |
34 | struct mod_list | |
35 | { | |
36 | const char *name; | |
37 | struct mod_list *next; | |
38 | }; | |
39 | ||
40 | /* Dependency. */ | |
41 | struct dep_list | |
42 | { | |
43 | const char *name; | |
44 | struct mod_list *list; | |
45 | struct dep_list *next; | |
46 | }; | |
47 | ||
48 | static char buf[1024]; | |
49 | ||
50 | static void | |
51 | free_mod_list (struct mod_list *head) | |
52 | { | |
53 | while (head) | |
54 | { | |
55 | struct mod_list *next; | |
56 | ||
57 | next = head->next; | |
58 | free ((void *) head->name); | |
59 | free (head); | |
60 | head = next; | |
61 | } | |
62 | } | |
63 | ||
64 | static void | |
65 | free_dep_list (struct dep_list *head) | |
66 | { | |
67 | while (head) | |
68 | { | |
69 | struct dep_list *next; | |
70 | ||
71 | next = head->next; | |
72 | free ((void *) head->name); | |
73 | free_mod_list (head->list); | |
74 | free (head); | |
75 | head = next; | |
76 | } | |
77 | } | |
78 | ||
79 | /* Read the list of dependencies. */ | |
80 | static struct dep_list * | |
81 | read_dep_list (FILE *fp) | |
82 | { | |
83 | struct dep_list *dep_list = 0; | |
b39f9d20 | 84 | |
6a161fa9 | 85 | while (fgets (buf, sizeof (buf), fp)) |
86 | { | |
87 | char *p; | |
88 | struct dep_list *dep; | |
89 | ||
90 | /* Get the target name. */ | |
91 | p = strchr (buf, ':'); | |
92 | if (! p) | |
6e0632e2 | 93 | grub_util_error (_("invalid line format: %s"), buf); |
6a161fa9 | 94 | |
95 | *p++ = '\0'; | |
96 | ||
97 | dep = xmalloc (sizeof (*dep)); | |
98 | dep->name = xstrdup (buf); | |
99 | dep->list = 0; | |
b39f9d20 | 100 | |
6a161fa9 | 101 | dep->next = dep_list; |
102 | dep_list = dep; | |
103 | ||
104 | /* Add dependencies. */ | |
105 | while (*p) | |
106 | { | |
107 | struct mod_list *mod; | |
108 | char *name; | |
109 | ||
4241d2b1 | 110 | /* Skip whitespace. */ |
88d51eff | 111 | while (*p && grub_isspace (*p)) |
6a161fa9 | 112 | p++; |
113 | ||
114 | if (! *p) | |
115 | break; | |
116 | ||
117 | name = p; | |
118 | ||
4241d2b1 | 119 | /* Skip non-whitespace. */ |
88d51eff | 120 | while (*p && ! grub_isspace (*p)) |
6a161fa9 | 121 | p++; |
122 | ||
123 | *p++ = '\0'; | |
b39f9d20 | 124 | |
6a161fa9 | 125 | mod = (struct mod_list *) xmalloc (sizeof (*mod)); |
126 | mod->name = xstrdup (name); | |
127 | mod->next = dep->list; | |
128 | dep->list = mod; | |
129 | } | |
130 | } | |
131 | ||
132 | return dep_list; | |
133 | } | |
134 | ||
135 | static char * | |
136 | get_module_name (const char *str) | |
137 | { | |
138 | char *base; | |
139 | char *ext; | |
b39f9d20 | 140 | |
6a161fa9 | 141 | base = strrchr (str, '/'); |
142 | if (! base) | |
143 | base = (char *) str; | |
144 | else | |
145 | base++; | |
146 | ||
147 | ext = strrchr (base, '.'); | |
148 | if (ext && strcmp (ext, ".mod") == 0) | |
149 | { | |
150 | char *name; | |
b39f9d20 | 151 | |
6a161fa9 | 152 | name = xmalloc (ext - base + 1); |
153 | memcpy (name, base, ext - base); | |
154 | name[ext - base] = '\0'; | |
155 | return name; | |
156 | } | |
b39f9d20 | 157 | |
6a161fa9 | 158 | return xstrdup (base); |
159 | } | |
160 | ||
161 | static char * | |
162 | get_module_path (const char *prefix, const char *str) | |
163 | { | |
164 | char *dir; | |
165 | char *base; | |
166 | char *ext; | |
167 | char *ret; | |
b39f9d20 | 168 | |
6a161fa9 | 169 | ext = strrchr (str, '.'); |
170 | if (ext && strcmp (ext, ".mod") == 0) | |
171 | base = xstrdup (str); | |
172 | else | |
173 | { | |
174 | base = xmalloc (strlen (str) + 4 + 1); | |
175 | sprintf (base, "%s.mod", str); | |
176 | } | |
b39f9d20 | 177 | |
6a161fa9 | 178 | dir = strchr (str, '/'); |
179 | if (dir) | |
180 | return base; | |
181 | ||
4b13b216 | 182 | ret = grub_util_get_path (prefix, base); |
6a161fa9 | 183 | free (base); |
184 | return ret; | |
185 | } | |
186 | ||
187 | static void | |
188 | add_module (const char *dir, | |
189 | struct dep_list *dep_list, | |
190 | struct mod_list **mod_head, | |
4b13b216 | 191 | struct grub_util_path_list **path_head, |
6a161fa9 | 192 | const char *name) |
193 | { | |
194 | char *mod_name; | |
4b13b216 | 195 | struct grub_util_path_list *path; |
6a161fa9 | 196 | struct mod_list *mod; |
197 | struct dep_list *dep; | |
b39f9d20 | 198 | |
6a161fa9 | 199 | mod_name = get_module_name (name); |
200 | ||
201 | /* Check if the module has already been added. */ | |
202 | for (mod = *mod_head; mod; mod = mod->next) | |
203 | if (strcmp (mod->name, mod_name) == 0) | |
204 | { | |
205 | free (mod_name); | |
206 | return; | |
207 | } | |
208 | ||
209 | /* Resolve dependencies. */ | |
210 | for (dep = dep_list; dep; dep = dep->next) | |
211 | if (strcmp (dep->name, mod_name) == 0) | |
212 | { | |
213 | for (mod = dep->list; mod; mod = mod->next) | |
214 | add_module (dir, dep_list, mod_head, path_head, mod->name); | |
215 | ||
216 | break; | |
217 | } | |
218 | ||
219 | /* Add this module. */ | |
220 | mod = (struct mod_list *) xmalloc (sizeof (*mod)); | |
221 | mod->name = mod_name; | |
222 | mod->next = *mod_head; | |
223 | *mod_head = mod; | |
224 | ||
225 | /* Add this path. */ | |
4b13b216 | 226 | path = (struct grub_util_path_list *) xmalloc (sizeof (*path)); |
6a161fa9 | 227 | path->name = get_module_path (dir, name); |
228 | path->next = *path_head; | |
229 | *path_head = path; | |
230 | } | |
231 | ||
4b13b216 | 232 | struct grub_util_path_list * |
233 | grub_util_resolve_dependencies (const char *prefix, | |
6a161fa9 | 234 | const char *dep_list_file, |
235 | char *modules[]) | |
236 | { | |
237 | char *path; | |
238 | FILE *fp; | |
239 | struct dep_list *dep_list; | |
240 | struct mod_list *mod_list = 0; | |
4b13b216 | 241 | struct grub_util_path_list *path_list = 0; |
977329f5 | 242 | |
4b13b216 | 243 | path = grub_util_get_path (prefix, dep_list_file); |
bb338aaf | 244 | fp = grub_util_fopen (path, "r"); |
6a161fa9 | 245 | if (! fp) |
0ae70393 | 246 | grub_util_error (_("cannot open `%s': %s"), path, strerror (errno)); |
6a161fa9 | 247 | |
248 | free (path); | |
249 | dep_list = read_dep_list (fp); | |
250 | fclose (fp); | |
251 | ||
252 | while (*modules) | |
253 | { | |
254 | add_module (prefix, dep_list, &mod_list, &path_list, *modules); | |
255 | modules++; | |
256 | } | |
257 | ||
258 | free_dep_list (dep_list); | |
259 | free_mod_list (mod_list); | |
260 | ||
977329f5 | 261 | { /* Reverse the path_list */ |
4b13b216 | 262 | struct grub_util_path_list *p, *prev, *next; |
977329f5 | 263 | |
264 | for (p = path_list, prev = NULL; p; p = next) | |
265 | { | |
266 | next = p->next; | |
267 | p->next = prev; | |
268 | prev = p; | |
269 | } | |
270 | ||
271 | return prev; | |
272 | } | |
6a161fa9 | 273 | } |
0e075ac3 AB |
274 | |
275 | void | |
276 | grub_util_free_path_list (struct grub_util_path_list *path_list) | |
277 | { | |
278 | struct grub_util_path_list *next; | |
279 | ||
280 | while (path_list) | |
281 | { | |
282 | next = path_list->next; | |
283 | free ((void *) path_list->name); | |
284 | free (path_list); | |
285 | path_list = next; | |
286 | } | |
287 | } |