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