wok view syslinux/stuff/iso2exe/iso2exe.c @ rev 18783

syslinux: set tz command line argument
author Pascal Bellard <pascal.bellard@slitaz.org>
date Sun Jan 03 13:17:18 2016 +0100 (2016-01-03)
parents d334cc1613e2
children ee7f5b80836f
line source
1 #ifdef __TURBOC__
2 #include <io.h>
3 #endif
4 #include <sys/types.h>
5 #include <fcntl.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #ifdef WIN32
10 #include <windows.h>
11 #endif
12 #ifdef __MSDOS__
13 int ftruncate(int fd, long newsize)
14 {
15 if (lseek(fd, newsize, SEEK_SET) != -1L)
16 return write(fd, NULL, 0);
17 return -1;
18 }
19 #endif
20 #ifdef __MINGW32__
21 #define ftruncate chsize
22 #endif
23 #if !defined(__MSDOS__) && !defined(WIN32)
24 #define O_BINARY 0
25 #endif
26 typedef unsigned char uint8_t;
27 typedef unsigned long uint32_t;
28 #include "iso2exe.h"
30 static int fd, forced, uninstall;
31 static unsigned status = 1;
32 static char *append, *initrd;
33 static char tazlitoinfo[0x8000U - BOOTISOSZ];
34 #define buffer tazlitoinfo
35 #define BUFFERSZ 2048
36 #define WORD(n) * (unsigned short *) (n)
37 #define LONG(n) * (unsigned long *) (n)
39 static void readsector(unsigned long sector)
40 {
41 if (lseek(fd, sector * BUFFERSZ, SEEK_SET) == -1 ||
42 read(fd, buffer, BUFFERSZ) != BUFFERSZ) {
43 puts(bootiso+READSECTORERR);
44 exit(1);
45 }
46 }
48 static unsigned long getcustomsector(void)
49 {
50 readsector(16UL);
51 return 16UL + LONG(buffer + 80);
52 }
54 static int skipmd5 = 0;
55 #define ALIGN1
57 typedef struct {
58 uint32_t l;
59 uint32_t h;
60 } uint64_t;
61 static uint8_t wbuffer[64]; /* always correctly aligned for uint64_t */
62 static uint64_t total64; /* must be directly before hash[] */
63 static uint32_t hash[8]; /* 4 elements for md5, 5 for sha1, 8 for sha256 */
65 //#define rotl32(x,n) (((x) << (n)) | ((x) >> (32 - (n))))
66 static uint32_t rotl32(uint32_t x, unsigned n)
67 {
68 return (x << n) | (x >> (32 - n));
69 }
71 static void md5_process_block64(void);
73 /* Feed data through a temporary buffer.
74 * The internal buffer remembers previous data until it has 64
75 * bytes worth to pass on.
76 */
77 static void common64_hash(const void *buffer, size_t len)
78 {
79 unsigned bufpos = total64.l & 63;
81 total64.l += len; if (total64.l < len) total64.h++;
83 while (1) {
84 unsigned remaining = 64 - bufpos;
85 if (remaining > len)
86 remaining = len;
87 /* Copy data into aligned buffer */
88 memcpy(wbuffer + bufpos, buffer, remaining);
89 len -= remaining;
90 buffer = (const char *)buffer + remaining;
91 bufpos += remaining;
92 /* clever way to do "if (bufpos != 64) break; ... ; bufpos = 0;" */
93 bufpos -= 64;
94 if (bufpos != 0)
95 break;
96 /* Buffer is filled up, process it */
97 md5_process_block64();
98 /*bufpos = 0; - already is */
99 }
100 }
102 /* Process the remaining bytes in the buffer */
103 static void common64_end(void)
104 {
105 unsigned bufpos = total64.l & 63;
106 /* Pad the buffer to the next 64-byte boundary with 0x80,0,0,0... */
107 wbuffer[bufpos++] = 0x80;
109 /* This loop iterates either once or twice, no more, no less */
110 while (1) {
111 unsigned remaining = 64 - bufpos;
112 memset(wbuffer + bufpos, 0, remaining);
113 /* Do we have enough space for the length count? */
114 if (remaining >= 8) {
115 /* Store the 64-bit counter of bits in the buffer */
116 //uint64_t t = total64 << 3;
117 uint32_t *t = (uint32_t *) (&wbuffer[64 - 8]);
118 /* wbuffer is suitably aligned for this */
119 //*(uint64_t *) (&wbuffer[64 - 8]) = t;
120 t[0] = total64.l << 3;
121 t[1] = (total64.h << 3) | (total64.l >> 29);
122 }
123 md5_process_block64();
124 if (remaining >= 8)
125 break;
126 bufpos = 0;
127 }
128 }
130 /* These are the four functions used in the four steps of the MD5 algorithm
131 * and defined in the RFC 1321. The first function is a little bit optimized
132 * (as found in Colin Plumbs public domain implementation).
133 * #define FF(b, c, d) ((b & c) | (~b & d))
134 */
135 #undef FF
136 #undef FG
137 #undef FH
138 #undef FI
139 #define FF(b, c, d) (d ^ (b & (c ^ d)))
140 #define FG(b, c, d) FF(d, b, c)
141 #define FH(b, c, d) (b ^ c ^ d)
142 #define FI(b, c, d) (c ^ (b | ~d))
144 /* Hash a single block, 64 bytes long and 4-byte aligned */
145 static void md5_process_block64(void)
146 {
147 uint32_t *words = (void*) wbuffer;
148 uint32_t A = hash[0];
149 uint32_t B = hash[1];
150 uint32_t C = hash[2];
151 uint32_t D = hash[3];
153 const uint32_t *pc;
154 const char *pp;
155 const char *ps;
156 int i;
157 uint32_t temp;
160 pc = C_array;
161 pp = P_array;
162 ps = S_array - 4;
164 for (i = 0; i < 64; i++) {
165 if ((i & 0x0f) == 0)
166 ps += 4;
167 temp = A;
168 switch (i >> 4) {
169 case 0:
170 temp += FF(B, C, D);
171 break;
172 case 1:
173 temp += FG(B, C, D);
174 break;
175 case 2:
176 temp += FH(B, C, D);
177 break;
178 case 3:
179 temp += FI(B, C, D);
180 }
181 temp += words[(int) (*pp++)] + *pc++;
182 temp = rotl32(temp, ps[i & 3]);
183 temp += B;
184 A = D;
185 D = C;
186 C = B;
187 B = temp;
188 }
189 /* Add checksum to the starting values */
190 hash[0] += A;
191 hash[1] += B;
192 hash[2] += C;
193 hash[3] += D;
195 }
196 #undef FF
197 #undef FG
198 #undef FH
199 #undef FI
201 /* Initialize structure containing state of computation.
202 * (RFC 1321, 3.3: Step 3)
203 */
204 static void md5_begin(void)
205 {
206 hash[0] = 0x67452301;
207 hash[1] = 0xefcdab89;
208 hash[2] = 0x98badcfe;
209 hash[3] = 0x10325476;
210 total64.l = total64.h = 0;
211 }
213 /* Used also for sha1 and sha256 */
214 #define md5_hash common64_hash
216 /* Process the remaining bytes in the buffer and put result from CTX
217 * in first 16 bytes following RESBUF. The result is always in little
218 * endian byte order, so that a byte-wise output yields to the wanted
219 * ASCII representation of the message digest.
220 */
221 #define md5_end common64_end
223 static int writenhash(void *buffer, size_t len)
224 {
225 md5_hash(buffer, len);
226 return write(fd, buffer, len);
227 }
229 static void md5sum(void)
230 {
231 unsigned long sectors = 0;
232 int count;
234 lseek(fd, 32768UL, SEEK_SET);
236 md5_begin();
237 while ((count = read(fd, buffer, BUFFERSZ)) > 0) {
238 if (sectors == 0)
239 sectors = LONG(buffer + 80);
240 md5_hash(buffer, count);
241 if (--sectors == 0)
242 break;
243 }
245 if (count < 0)
246 return;
248 md5_end();
250 lseek(fd, 32752UL, SEEK_SET);
251 write(fd, hash, 16);
252 memcpy(bootiso + BOOTISOSZ - 16, hash, 16);
253 }
255 static unsigned chksum(unsigned start, unsigned stop)
256 {
257 unsigned i, n = 0;
259 lseek(fd, 0UL /* (unsigned long) (start / BUFFERSZ) */, SEEK_SET);
260 while (1) {
261 if (read(fd, buffer, BUFFERSZ) != BUFFERSZ)
262 return 0;
263 for (i = start % BUFFERSZ; i < BUFFERSZ; i += 2, start += 2) {
264 if (start >= stop)
265 return - n;
266 n += WORD(buffer + i);
267 }
268 }
269 }
271 static unsigned clear_config(unsigned i)
272 {
273 for (;i % 512; i++) {
274 /* clear custom config */
275 write(fd, buffer + 2048, 2048);
276 }
277 return i;
278 }
280 static unsigned install(char *filename)
281 {
282 #define heads 64
283 #define sectors 32
284 #define partition (446+16)
285 #define trksz (512UL * heads * sectors)
286 unsigned long size, catalog, lba;
287 int cylinders, i, j, isohybrid;
288 unsigned n;
289 #ifdef __MSDOS__
290 for (bootiso = (char *) install;
291 bootiso[0] != 'M' || bootiso[1] != 'Z' || bootiso[2] != '\xEB';
292 bootiso++) if (bootiso < (char *) install) {
293 bootiso = "No bootiso data";
294 return 0;
295 }
296 #endif
297 if (!filename)
298 return USAGE;
299 fd = open(filename,O_RDWR|O_BINARY);
300 if (fd == -1)
301 return OPENERR;
303 if (uninstall) {
304 struct { char check[sizeof(tazlitoinfo) - BUFFERSZ - 1024]; };
305 readsector(0UL);
306 n = BUFFERSZ; /* fill with zeros */
307 if (WORD(buffer) == 23117) {
308 /* restore isolinux hybrid boot */
309 readsector((unsigned long) buffer[417]);
310 n = 0; /* fill with hybrid boot */
311 }
312 lseek(fd, 0UL, SEEK_SET);
313 for (i = 0; i < 32; i++, n = BUFFERSZ) {
314 write(fd, buffer + n, 1024);
315 }
316 i = getcustomsector();
317 lseek(fd, i * 2048UL, SEEK_SET);
318 i = clear_config(i);
319 ftruncate(fd, i * 2048UL);
320 close(fd);
321 status = 0;
322 return UNINSTALLMSG;
323 }
325 readsector(0UL);
326 if (buffer[0] == 'M' && buffer[1] == 'Z') {
327 if (forced == 0)
328 return ALREADYEXEERR;
329 n = (buffer[417] + 1) * 512;
330 i = 0x8000 - 1024;
331 if (i > sizeof(tazlitoinfo))
332 i = sizeof(tazlitoinfo);
333 if (lseek(fd, n, SEEK_SET) == -1 ||
334 read(fd, tazlitoinfo, sizeof(tazlitoinfo)) != sizeof(tazlitoinfo) ||
335 lseek(fd, 1024UL, SEEK_SET) == -1 ||
336 write(fd, tazlitoinfo, i) != i) {
337 puts(bootiso+READSECTORERR);
338 exit(1);
339 }
340 }
342 do {
343 /* Install hybridiso boot sector */
344 readsector(17UL);
345 status = ELTORITOERR;
346 if (strncmp(buffer+7, bootiso+ELTORITOERR+ELTORITOOFS, 23))
347 break;
348 catalog = LONG(buffer + 71);
349 readsector(catalog);
350 status = CATALOGERR;
351 if (LONG(buffer) != 1 || LONG(buffer + 30) != 0x88AA55UL)
352 break;
353 lba = LONG(buffer + 40);
354 readsector(lba);
355 status = HYBRIDERR;
356 if (LONG(buffer + 64) != 1886961915UL)
357 break;
358 isohybrid = bootiso[417] * 512;
359 LONG(bootiso + isohybrid + 432) = lba * 4;
360 LONG(bootiso + isohybrid + 440) = rand();
361 LONG(bootiso + isohybrid + partition) = 0x10080UL;
362 WORD(bootiso + isohybrid + 510) = 0xAA55U;
363 #if 0
364 size = lseek(fd, 0UL, SEEK_END);
365 size += 0x000FFFFFUL;
366 size &= 0xFFF00000UL;
367 #else
368 for (size = 0x000FFFFFUL; /* 1M - 1 */
369 read(fd, tazlitoinfo, 1024) == 1024;
370 size += 1024);
371 size &= 0xFFF00000UL; /* round */
372 #endif
373 cylinders = (size >> 20) - 1;
374 bootiso[isohybrid + partition + 4] = 23; /* "Windows hidden IFS" */
375 bootiso[isohybrid + partition + 5] = heads - 1;
376 bootiso[isohybrid + partition + 6] = ((cylinders & 0x300) >> 2) + sectors;
377 bootiso[isohybrid + partition + 7] = cylinders & 0xFF;
378 LONG(bootiso + isohybrid + partition + 8) = 0;
379 LONG(bootiso + isohybrid + partition + 12) = (size >> 9);
381 /* Copy the partition table */
382 memcpy(bootiso + 0x1BE, bootiso + isohybrid + 0x1BE, 66);
383 status = 0;
384 } while (0);
386 if (forced == 0 && status)
387 return status;
389 status = 1;
390 if (append || initrd) {
391 unsigned long pos = getcustomsector() * 2048UL;
392 lseek(fd, pos, SEEK_SET);
393 clear_config(pos);
394 lseek(fd, pos, SEEK_SET);
395 write(fd, "#!boot 00000000000000000000000000000000\n", 40);
396 md5_begin();
397 if (append) {
398 writenhash("append=", 7);
399 writenhash(append, strlen(append));
400 writenhash("\n", 1);
401 }
402 if (initrd) {
403 char number[16], *p;
404 unsigned long end, x;
405 int data = open(initrd,O_RDONLY|O_BINARY);
406 if (data == -1)
407 return OPENINITRDERR;
408 for (end = 0;; end += i) {
409 i = read(data, buffer, BUFFERSZ);
410 if (i <= 0)
411 break;
412 }
413 p = number + sizeof(number) -1;
414 x = end; *p-- = '\n';
415 do {
416 *p-- = '0' + (x % 10);
417 x /= 10;
418 } while (x);
419 if (*++p != '0') {
420 writenhash("initrd:", 7);
421 i = number - p + sizeof(number);
422 writenhash(p, i);
423 lseek(data, 0UL, SEEK_SET);
424 do {
425 i = read(data, buffer, BUFFERSZ);
426 if (i <= 0)
427 break;
428 if (i > end)
429 i = end;
430 writenhash(buffer, i);
431 end -= i;
432 } while (end != 0);
433 }
434 close(data);
435 }
436 md5_end();
437 {
438 static char h[] = "0123456789abcdef";
439 char string[32], *s = string + 30;
440 unsigned char *p = (void *) hash;
442 lseek(fd, 7 + pos, SEEK_SET);
443 for (p += 15; s >= string; p--, s -= 2) {
444 s[1] = h[ *p & 15 ];
445 s[0] = h[ *p >> 4 ];
446 }
447 write(fd, string, 32);
448 }
449 }
451 /* Install iso2exe boot sector */
452 LONG(bootiso + 440) = time(NULL);
454 /* read tazlito flavor data */
455 lseek(fd, 1024UL, SEEK_SET);
456 read(fd, tazlitoinfo, sizeof(tazlitoinfo));
458 /* Update iso image */
459 n = (bootiso[417] + 1) * 512;
460 lseek(fd, 0UL, SEEK_SET);
461 write(fd, bootiso, n); /* EXE/PE + isohybrid mbr */
462 write(fd, tazlitoinfo, sizeof(tazlitoinfo));
463 write(fd, bootiso + n, BOOTISOSZ - n); /* COM + rootfs + EXE/DOS */
465 /* Compute the boot checksums */
466 if (!skipmd5) {
467 puts(bootiso + MD5MSG);
468 md5sum();
469 lseek(fd, 0UL, SEEK_SET);
470 write(fd, bootiso, 512);
471 n = WORD(bootiso + 2) - 512*(WORD(bootiso + 4) - 1);
472 WORD(bootiso + 18) = chksum(0, (unsigned short) n) - 1;
473 }
474 lseek(fd, 0UL, SEEK_SET);
475 write(fd, bootiso, 512);
476 close(fd);
477 status = 0;
478 return SUCCESSMSG;
479 }
481 int main(int argc, char *argv[])
482 {
483 int i;
484 char *s;
486 while (argc > 2) {
487 s = argv[1];
488 if (*s != '-') break;
489 while (*s == '-') s++;
490 switch (*s | 0x20) {
491 case 'a' : append=argv[2]; break;
492 case 'i' : initrd=argv[2]; break;
493 }
494 argv += 2;
495 argc -= 2;
496 }
497 for (i = 2; i < argc; i++) {
498 char *s = argv[i];
499 while ((unsigned)(*s - '-') <= ('/' - '-')) s++;
500 switch (*s | 0x20) {
501 case 'f' : forced++; break;
502 case 'q' : skipmd5++; break;
503 case 'u' : uninstall++; break;
504 }
505 }
506 puts(bootiso + install(argv[1]));
507 if (status > 1)
508 puts(bootiso + FORCEMSG);
509 #ifdef WIN32
510 Sleep(2000);
511 #endif
512 return status;
513 }