Import of openhackware-0.4.1
[openhackware.git] / src / libexec / chrp.c
blob9a2be2ea818a85e16e9ffe3085b1516efc857ec5
1 /*
2 * <chrp.c>
4 * Open Hack'Ware BIOS CHRP boot file loader
5 *
6 * Copyright (c) 2004-2005 Jocelyn Mayer
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License V2
10 * as published by the Free Software Foundation
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <ctype.h>
25 #include "bios.h"
26 #include "exec.h"
27 #include "libfs/libfs.h"
29 /* Simple XML parser */
30 typedef struct XML_tag_t XML_tag_t;
31 struct XML_tag_t {
32 unsigned char *name;
33 XML_tag_t *up;
34 int dlen;
35 void *data;
38 enum {
39 CHRP_TAG_UNKNOWN = 0,
40 CHRP_TAG_CHRP_BOOT,
41 CHRP_TAG_COMPATIBLE,
42 CHRP_TAG_DESCRIPTION,
43 CHRP_TAG_BOOT_SCRIPT,
44 CHRP_TAG_OS_BADGE_ICONS,
45 CHRP_TAG_ICON,
46 CHRP_TAG_BITMAP,
47 CHRP_TAG_LICENSE,
50 enum {
51 CHRP_SCRIPT_IGNORE = 0,
52 CHRP_SCRIPT_LOAD_BOOT,
53 CHRP_SCRIPT_EMBEDDED,
56 enum {
57 XML_STATE_OUT = 0,
58 XML_STATE_TAG,
59 XML_STATE_DATA,
62 static int XML_get_type (const unsigned char *name)
64 int ret;
66 if (strcmp(name, "CHRP-BOOT") == 0)
67 ret = CHRP_TAG_CHRP_BOOT;
68 else if (strcmp(name, "COMPATIBLE") == 0)
69 ret = CHRP_TAG_COMPATIBLE;
70 else if (strcmp(name, "DESCRIPTION") == 0)
71 ret = CHRP_TAG_DESCRIPTION;
72 else if (strcmp(name, "BOOT-SCRIPT") == 0)
73 ret = CHRP_TAG_BOOT_SCRIPT;
74 else if (strcmp(name, "OS-BADGE-ICONS") == 0)
75 ret = CHRP_TAG_OS_BADGE_ICONS;
76 else if (strcmp(name, "ICON") == 0)
77 ret = CHRP_TAG_ICON;
78 else if (strcmp(name, "BITMAP") == 0)
79 ret = CHRP_TAG_BITMAP;
80 else if (strcmp(name, "LICENSE") == 0)
81 ret = CHRP_TAG_LICENSE;
82 else
83 ret = CHRP_TAG_UNKNOWN;
85 return ret;
88 static unsigned char *strfind (const unsigned char *buf, const unsigned char *str)
90 const unsigned char *pos;
91 int len = strlen(str);
93 // DPRINTF("Look for '%s' in \n'%s'\n", str, buf);
94 for (pos = buf; *pos != '\0'; pos++) {
95 if (memcmp(pos, str, len) == 0)
96 return (unsigned char *)pos;
99 return NULL;
102 int exec_load_chrp (inode_t *file, void **dest, void **entry, void **end,
103 uint32_t loffset)
105 #define TMPNAME_LEN 512
106 unsigned char tmpname[TMPNAME_LEN], *tmpp, *buf, *pos, *endc, c;
107 XML_tag_t *tag, *tmp, *first;
108 part_t *part;
109 inode_t *inode;
110 int state;
111 int script_type = CHRP_SCRIPT_IGNORE;
112 uint32_t crc, offset = 0;
113 int ret, rel = 0;
115 buf = malloc(16384);
116 /* Check the file head */
117 file_seek(file, loffset);
118 fs_read(file, buf, 11);
119 if (memcmp(buf, "<CHRP-BOOT>", 11) != 0) {
120 ERROR("Not an Apple CHRP boot file !\n");
121 return -2;
123 /* Re-seek at start of the file and start parsing it */
124 file_seek(file, loffset);
125 pos = buf;
126 tag = NULL;
127 first = NULL;
128 ret = -1;
129 fs_read(file, &c, 1);
130 offset++;
131 for (state = XML_STATE_TAG; state != XML_STATE_OUT;) {
132 /* Get next char */
133 fs_read(file, &c, 1);
134 offset++;
135 if ((state == XML_STATE_TAG && c != '>') ||
136 (state == XML_STATE_DATA && c != '<')) {
137 *pos++ = c;
138 continue;
140 *pos++ = '\0';
141 switch (state) {
142 case XML_STATE_TAG:
143 if (*buf == '/') {
144 if (tag == NULL || strcmp(buf + 1, tag->name) != 0) {
145 ERROR("XML error: open name: '%s' close name: '%s'\n",
146 buf + 1, tag->name);
147 goto out;
149 DPRINTF("Close tag: '%s'\n", tag->name);
150 switch (XML_get_type(tag->name)) {
151 case CHRP_TAG_CHRP_BOOT:
152 /* Nothing to do */
153 break;
154 case CHRP_TAG_COMPATIBLE:
155 /* Won't check... */
156 pos = tag->data;
157 if (*(char *)tag->data == 0x0d) {
158 pos++;
160 DPRINTF("Compatible: '%s'\n", pos);
161 break;
162 case CHRP_TAG_DESCRIPTION:
163 pos = tag->data;
164 if (*(char *)tag->data == 0x0d) {
165 pos++;
167 DPRINTF("Description: '%s'\n", pos);
168 break;
169 case CHRP_TAG_BOOT_SCRIPT:
170 /* Here is the interresting part... */
171 crc = crc32(0, tag->data, tag->dlen);
172 #if 0
173 DPRINTF("Forth script: %08x\n%s\n",
174 crc, (char *)tag->data);
175 #endif
176 switch (crc) {
177 case 0x5464F92C:
178 /* Mandrake 9.1 CD1 boot script */
179 case 0x4BC74ECF:
180 /* Mandrake 10.1 & 10.2 CD1 boot script */
181 case 0x5B265246:
182 /* Gentoo 1.2-r1 */
183 /* Gentoo 2004.1 minimal install CD */
184 /* Gentoo 1.4 live CDROM */
185 /* Knopix PPC beta-pre12 */
186 case 0x75420D8A:
187 /* Debian woody */
188 /* Debian 3.0r1 */
189 script_type = CHRP_SCRIPT_LOAD_BOOT;
190 goto do_script;
191 case 0x633e4c9c:
192 /* Debian Sarge */
193 case 0xbe3abf60:
194 /* Debian Sarge, installed on a hard disk drive */
195 script_type = CHRP_SCRIPT_LOAD_BOOT;
196 goto do_script;
197 case 0x07b86bfe:
198 /* Linux Fedora Core 3 */
199 script_type = CHRP_SCRIPT_LOAD_BOOT;
200 goto do_script;
201 case 0x9ccdf371:
202 script_type = CHRP_SCRIPT_LOAD_BOOT;
203 goto do_script;
204 case 0xEF423926:
205 /* OpenBSD 3.4 */
206 case 0x68e4f265:
207 /* OpenBSD 3.5 */
208 case 0x3b7ea9e1:
209 /* OpenBSD 3.6 */
210 script_type = CHRP_SCRIPT_LOAD_BOOT;
211 goto do_script;
212 case 0xB7981DBC:
213 /* iBook 2 hw test CDROM */
214 #if 1
215 script_type = CHRP_SCRIPT_LOAD_BOOT;
216 goto do_script;
217 #endif
219 case 0xEA06C1A7:
220 /* MacOS 9.2 boot script:
221 * the XCOFF loader is embedded in the file...
223 case 0x53A95958:
224 /* iBook 2 restore CD (MacOS X 10.2) */
225 script_type = CHRP_SCRIPT_EMBEDDED;
226 pos = strfind(tag->data, "elf-offset");
227 if (pos != NULL) {
228 /* Go backward until we get the value */
229 for (--pos; *pos < '0' || *pos > '9'; pos--)
230 continue;
231 for (; *pos >= '0' && *pos <= '9'; pos--)
232 continue;
233 offset = strtol(pos, NULL, 16);
234 goto do_script;
236 ERROR("Didn't find boot file offset\n");
237 goto out;
238 case 0x8d5acb86:
239 /* Darwin-7.01
240 * The executable file is embedded after the script
242 script_type = CHRP_SCRIPT_EMBEDDED;
243 DPRINTF("Boot file embedded at the end of boot script\n");
244 break;
245 default:
246 ERROR("XML error: unknown Forth script: %08x\n%s\n",
247 crc, (char *)tag->data);
248 goto out;
250 break;
252 do_script:
253 switch (script_type) {
254 case CHRP_SCRIPT_LOAD_BOOT:
255 pos = strfind(tag->data, "boot");
256 if (pos != NULL) {
257 /* Eat everything until file name */
258 for (pos += 4; *pos != ','; pos++)
259 continue;
260 /* Eat ',' */
261 for (++pos; isspace(*pos) || *pos == '"'; pos++)
262 continue;
263 /* Find file name end */
264 redo:
265 for (endc = pos;
266 *endc != ' ' && *endc != '"' &&
267 *endc != '\n' && *endc != '\r';
268 endc++) {
269 if (*endc == '\\')
270 *endc = '/';
272 if (memcmp(pos, "ofwboot", 7) == 0) {
273 for (pos = endc + 1; *pos == ' '; pos++)
274 continue;
275 goto redo;
277 *endc = '\0';
279 DPRINTF("Real boot file is: '%s'\n", pos);
280 part = fs_inode_get_part(file);
281 /* check if it's a path or just a file */
282 tmpp = pos;
283 if ((pos[0] == '/' && pos[1] == '/') ||
284 pos[0] != '/') {
285 unsigned char *bootdir;
286 bootdir = fs_get_boot_dirname(part_fs(part));
287 if (bootdir == NULL) {
288 ERROR("Cannot get boot directory name\n");
289 bug();
291 snprintf(tmpname, TMPNAME_LEN,
292 "%s/%s", bootdir, pos);
293 tmpname[TMPNAME_LEN - 1] = '\0';
294 rel++;
295 pos = tmpname;
296 DPRINTF("'%s' => '%s'\n", bootdir, pos);
298 retry:
299 inode = fs_open(part_fs(part), pos);
300 if (inode == NULL) {
301 ERROR("Real boot inode '%s' not found\n", pos);
302 /* Try in root directory */
303 if (rel == 1) {
304 for (; *tmpp == '/'; tmpp++)
305 continue;
306 snprintf(tmpname, TMPNAME_LEN, "/%s", tmpp);
307 tmpname[TMPNAME_LEN - 1] = '\0';
308 rel++;
309 goto retry;
312 bug();
314 ret = _bootfile_load(inode, dest, entry, end, 0, -1);
315 fs_close(inode);
316 goto out;
317 case CHRP_SCRIPT_EMBEDDED:
318 DPRINTF("Exec offset: %d %08x\n", offset, offset);
319 ret = 0;
320 goto out;
321 case CHRP_SCRIPT_IGNORE:
322 break;
324 break;
325 case CHRP_TAG_OS_BADGE_ICONS:
326 case CHRP_TAG_ICON:
327 /* Ignore it */
328 break;
329 case CHRP_TAG_BITMAP:
330 /* Ignore it */
331 break;
332 case CHRP_TAG_LICENSE:
333 /* Ignore it */
334 pos = tag->data;
335 if (*(char *)tag->data == 0x0d) {
336 pos++;
338 DPRINTF("License: '%s'\n", pos);
339 break;
340 default:
341 ERROR("XML error: unknown tag: '%s'\n", tag->name);
342 goto out;
344 tmp = tag->up;
345 if (tmp == NULL)
346 state = XML_STATE_OUT;
347 else
348 state = XML_STATE_DATA;
349 free(tag->name);
350 free(tag->data);
351 free(tag);
352 tag = tmp;
353 } else {
354 tmp = malloc(sizeof(XML_tag_t));
355 if (tmp == NULL) {
356 ERROR("Cannot allocate new tag\n");
357 goto out;
359 tmp->up = tag;
360 /* Ignore tag attributes */
361 pos = strchr(buf, ' ');
362 if (pos != NULL)
363 *pos = '\0';
364 tmp->name = strdup(buf);
365 tag = tmp;
366 if (first == NULL)
367 first = tag;
368 DPRINTF("Open tag '%s'\n", tag->name);
369 state = XML_STATE_DATA;
371 break;
372 case XML_STATE_DATA:
373 if (tag->data == NULL) {
374 tag->dlen = pos - buf;
375 tag->data = malloc(tag->dlen);
376 memcpy(tag->data, buf, tag->dlen);
378 state = XML_STATE_TAG;
379 break;
381 pos = buf;
383 ret = 0;
384 fs_read(file, &c, 1);
385 fs_read(file, &c, 1);
386 offset += 2;
387 out:
388 #if 1
389 for (; tag != NULL; tag = tmp) {
390 tmp = tag->up;
391 free(tag->name);
392 free(tag->data);
393 free(tag);
395 #endif
396 if (ret == 0 && script_type == CHRP_SCRIPT_EMBEDDED) {
397 DPRINTF("Load embedded file from offset %d (%d => %d)\n",
398 offset, loffset, loffset + offset);
399 ret = _bootfile_load(file, dest, entry, end, loffset + offset, -1);
401 DPRINTF("Done\n");
403 return ret;