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