wok view syslinux/stuff/iso2exe/iso2exe.sh @ rev 18897

syslinux/isohybrid.exe add -r support
author Pascal Bellard <pascal.bellard@slitaz.org>
date Sun Feb 14 22:06:06 2016 +0100 (2016-02-14)
parents fc572791f0a0
children 62104f2454a3
line source
1 #!/bin/sh
3 ddq()
4 {
5 dd $@ 2> /dev/null
6 }
8 store()
9 {
10 n=$2; for i in $(seq 8 8 ${4:-16}); do
11 printf '\\\\x%02X' $(($n & 255))
12 n=$(($n >> 8))
13 done | xargs echo -en | ddq bs=1 conv=notrunc of=$3 seek=$(($1))
14 }
16 get()
17 {
18 echo $(od -j $(($1)) -N ${3:-2} -t u${3:-2} -An "$2")
19 }
21 compress()
22 {
23 if [ "$1" ]; then
24 gzip -9 > $1
25 [ "$(which advdef 2> /dev/null)" ] &&
26 advdef -z4 $1 > /dev/null
27 elif [ "$(which xz 2> /dev/null)" ]; then
28 xz -z -e --format=lzma --lzma1=mode=normal --stdout
29 else
30 lzma e -si -so
31 fi 2> /dev/null
32 }
34 add_rootfs()
35 {
36 TMP=/tmp/iso2exe$$
37 mkdir -p $TMP/dev
38 cp -a /dev/tty /dev/tty0 $TMP/dev
39 $0 --get init > $TMP/init.exe
40 # mount -o loop,ro $1 $TMP
41 # oldslitaz="$(ls $TMP/boot/isolinux/splash.lss 2> /dev/null)"
42 # umount -d $TMP
43 # [ "$oldslitaz" ] && # for SliTaz <= 3.0 only...
44 # grep -q mount.posixovl.iso2exe $TMP/init.exe && mkdir $TMP/bin &&
45 # cp /usr/sbin/mount.posixovl $TMP/bin/mount.posixovl.iso2exe \
46 # 2> /dev/null && echo "Store mount.posixovl ($(wc -c \
47 # < /usr/sbin/mount.posixovl) bytes) ..."
48 find $TMP -type f -print0 | xargs -0 chmod +x
49 ( cd $TMP ; find * | cpio -o -H newc ) | compress $TMP/rootfs.gz
50 SIZE=$(wc -c < $TMP/rootfs.gz)
51 store 24 $SIZE $1
52 OFS=$(( $OFS - $SIZE ))
53 printf "Adding rootfs.gz file at %04X (%d bytes) ...\n" $OFS $SIZE
54 cat $TMP/rootfs.gz | ddq of=$1 bs=1 seek=$OFS conv=notrunc
55 rm -rf $TMP
56 }
58 add_dosexe()
59 {
60 TMP=/tmp/bootiso$$
61 $0 --get bootiso.bin > $TMP 2> /dev/null
62 OFS=$(($(get 20 $TMP) - 0xC0))
63 printf "Adding DOS/EXE stub at %04X (%d bytes) ...\n" $OFS $((0x8000 - $OFS))
64 ddq if=$TMP bs=1 skip=$OFS of=$1 seek=$OFS conv=notrunc
65 rm -f $TMP
66 }
68 add_doscom()
69 {
70 SIZE=$($0 --get boot.com | wc -c)
71 OFS=$(( $OFS - $SIZE ))
72 printf "Adding DOS boot file at %04X (%d bytes) ...\n" $OFS $SIZE
73 $0 --get boot.com | ddq of=$1 bs=1 seek=$OFS conv=notrunc
74 store 64 $(($OFS+0xC0)) $1
75 }
77 add_tazlito_info()
78 {
79 HOLE=$OFS
80 [ $(get 0 $2) -eq 35615 ] || return
81 zcat $2 | gzip -9 > /tmp/rezipped$$.gz
82 [ "$(which advdef 2> /dev/null)" ] &&
83 advdef -z4 /tmp/rezipped$$.gz > /dev/null
84 n=$(stat -c %s /tmp/rezipped$$.gz)
85 printf "Moving tazlito data record at %04X ($n bytes) ...\n" $OFS
86 ddq if=/tmp/rezipped$$.gz bs=1 of=$1 seek=$OFS conv=notrunc
87 HOLE=$(($HOLE+$n))
88 rm -f /tmp/rezipped$$.gz
89 }
91 add_win32exe()
92 {
93 SIZE=$($0 --get win32.exe 2> /dev/null | tee /tmp/exe$$ | wc -c)
94 printf "Adding WIN32 file at %04X (%d bytes) ...\n" 0 $SIZE
95 ddq if=/tmp/exe$$ of=$1 conv=notrunc
96 printf "Adding bootiso head at %04X...\n" 0
97 $0 --get bootiso.bin 2> /dev/null > /tmp/exe$$
98 ddq if=/tmp/exe$$ of=$1 bs=128 count=1 conv=notrunc
99 store $((0x94)) $((0xE0 - 12*8)) $1
100 store $((0xF4)) $((16 - 12)) $1
101 ddq if=$1 of=/tmp/coff$$ bs=1 skip=$((0x178)) count=$((0x88))
102 ddq if=/tmp/coff$$ of=$1 conv=notrunc bs=1 seek=$((0x178 - 12*8))
103 ddq if=/tmp/exe$$ of=$1 bs=1 count=24 seek=$((0x1A0)) skip=$((0x1A0)) conv=notrunc
104 ddq if=$2 bs=1 skip=$((0x1B8)) seek=$((0x1B8)) count=72 of=$1 conv=notrunc
105 store 417 $(($SIZE/512)) $1 8
106 store 510 $((0xAA55)) $1
107 rm -f /tmp/exe$$ /tmp/coff$$
108 printf "Moving syslinux hybrid boot record at %04X (512 bytes) ...\n" $SIZE
109 ddq if=$2 bs=1 count=512 of=$1 seek=$SIZE conv=notrunc
110 OFS=$(($SIZE+512))
111 }
113 add_fdbootstrap()
114 {
115 SIZE=$($0 --get bootfd.bin 2> /dev/null | wc -c)
116 if [ $SIZE -ne 0 ]; then
117 SIZE=$(( $SIZE - 512 )) # sector 2 is data
118 OFS=$(( $OFS - $SIZE ))
119 printf "Adding floppy bootstrap file at %04X (%d bytes) ...\n" $OFS $SIZE
120 $0 --get bootfd.bin | \
121 ddq of=$1 bs=1 count=512 seek=$OFS conv=notrunc
122 $0 --get bootfd.bin | \
123 ddq of=$1 bs=1 skip=1024 seek=$((512 + $OFS)) conv=notrunc
124 store 26 $(($SIZE/512)) $1 8
125 fi
126 }
128 gzsize()
129 {
130 echo $(($(hexdump -C | awk ' {
131 for (i = 2; i < 18; i++) if ($i != "00") break;
132 if (i == 18) {
133 for (i = 17; i > 1; i--) if ($i != "00") break;
134 print "0x" $1 " + 2 - " (16 - i)
135 exit
136 }
137 }')))
138 }
140 fileofs()
141 {
142 [ $(get 1024 "$ISO") -eq 35615 ] && i=1024 ||
143 i=$((512*(1+$(get 417 "$ISO" 1))))
144 stub=$(($(get 20 "$ISO") - 0xC0))
145 c=$(custom_config_sector "$ISO")
146 SIZE=0; OFFSET=0
147 case "$1" in
148 win32.exe) [ $i -eq 1024 ] || SIZE=$(($i - 512));;
149 syslinux.mbr) [ $i -eq 1024 ] || OFFSET=$(($i - 512)); SIZE=512;;
150 flavor.info) OFFSET=$i
151 SIZE=$(ddq bs=512 skip=$(($i/512)) if="$ISO" | gzsize);;
152 floppy.boot) SIZE=$(($(get 26 "$ISO" 1)*512))
153 OFFSET=$(($(get 64 "$ISO") - 0xC0 - $SIZE));;
154 rootfs.gz) SIZE=$(get 24 "$ISO"); OFFSET=$(($stub - $SIZE));;
155 tazboot.com) OFFSET=$(($(get 64 "$ISO") - 0xC0))
156 SIZE=$(($stub - $(get 24 "$ISO") - $OFFSET));;
157 dosstub) OFFSET=$stub; SIZE=$((0x8000 - $OFFSET));;
158 boot.md5) OFFSET=$((0x7FF0)); SIZE=16;;
159 fs.iso) OFFSET=$((0x8000))
160 SIZE=$((2048*$c - $OFFSET));;
161 custom.magic) ddq bs=2k skip=$c if="$ISO" | ddq bs=1 count=6 | \
162 grep -q '#!boot' && OFFSET=$((2048*$c)) &&
163 SIZE=39 ;;
164 custom.append) OFFSET=$((2048*$c+47)) &&
165 SIZE=$(ddq bs=2k skip=$c if="$ISO" count=1 | \
166 sed '/^append=/!d;s/^[^=]*=.//' | wc -c);;
167 custom.initrd) i=$(ddq bs=2k skip=$c if="$ISO" count=1 | \
168 sed '/^append=\|^initrd:/!d' | wc -c)
169 OFFSET=$((2048*$c+$i+40))
170 SIZE=$(($(ddq bs=2k skip=$c if="$ISO" count=1 | \
171 sed '/^initrd:/!d;s/.*://') + 0));;
172 esac
173 }
175 list()
176 {
177 HEAP=0
178 for f in win32.exe syslinux.mbr flavor.info floppy.boot tazboot.com \
179 rootfs.gz dosstub boot.md5 fs.iso custom.magic custom.append \
180 custom.initrd; do
181 fileofs $f
182 [ $SIZE -le 0 ] && continue
183 [ "${OFFSET:8}" ] && continue
184 [ $OFFSET -lt 0 ] && continue
185 [ $(get $OFFSET "$ISO") -eq 0 ] && continue
186 [ $OFFSET -gt $HEAP ] && [ $(($OFFSET - $HEAP)) -gt 16 ] &&
187 printf "%d free bytes in %04X..%04X\n" $(($OFFSET - $HEAP)) $HEAP $OFFSET
188 [ $OFFSET -ge $HEAP ] && HEAP=$(($OFFSET+$SIZE))
189 printf "$f at %04X ($SIZE bytes).\n" $OFFSET
190 done
191 OFFSET=$(stat -c %s "$ISO")
192 [ $OFFSET -gt $HEAP ] &&
193 printf "%d free bytes in %04X..%04X\n" $(($OFFSET - $HEAP)) $HEAP $OFFSET
194 }
196 extract()
197 {
198 for f in $@; do
199 fileofs $f
200 [ $SIZE -eq 0 ] ||
201 ddq bs=1 count=$SIZE skip=$OFFSET if="$ISO" >$f
202 done
203 }
205 custom_config_sector()
206 {
207 echo $(($(get 32848 "$1" 4)+16))
208 }
210 clear_custom_config()
211 {
212 start=$(custom_config_sector $1)
213 cnt=$((512 - ($start % 512)))
214 [ $cnt -ne 512 ] &&
215 ddq if=/dev/zero of=$1 bs=2k seek=$start count=$cnt
216 }
217 case "$1" in
218 --build)
219 shift
220 ls -l $@
221 cat >> $0 <<EOM
222 $(tar cf - $@ | compress | uuencode -m -)
223 EOT
224 EOM
225 sed -i '/^case/,/^esac/d' $0
226 exit ;;
227 --get)
228 cat $2
229 exit ;;
230 --array)
231 DATA=/tmp/dataiso$$
232 ddq if=/dev/zero bs=32k count=1 of=$DATA
233 add_win32exe $DATA $2 > /dev/null
234 HSZ=$OFS
235 add_dosexe $DATA > /dev/null
236 add_rootfs $DATA > /dev/null
237 add_doscom $DATA > /dev/null
238 add_fdbootstrap $DATA > /dev/null
239 name=${3:-bootiso}
240 BOOTISOSZ=$((0x8000 - $OFS + $HSZ))
241 cat <<EOT
243 #define $(echo $name | tr '[a-z]' '[A-Z]')SZ $BOOTISOSZ
245 #ifndef __MSDOS__
246 static char $name[] = {
247 /* head */
248 $(hexdump -v -n $HSZ -e '" " 16/1 "0x%02X, "' -e '" // %04.4_ax |" 16/1 "%_p" "| \n"' $DATA | sed 's/ 0x ,/ /g')
249 /* tail */
250 $(hexdump -v -s $OFS -e '" " 16/1 "0x%02X, "' -e '" // %04.4_ax |" 16/1 "%_p" "| \n"' $DATA | sed 's/ 0x ,/ /g')
252 /* These strange constants are defined in RFC 1321 as
253 T[i] = (int)(4294967296.0 * fabs(sin(i))), i=1..64
254 */
255 /* static const uint32_t C_array[64] */
256 EOT
257 while read a b c d; do
258 for i in $a $b $c $d; do
259 echo $i | sed 's/0x\(..\)\(..\)\(..\)\(..\),/0x\4, 0x\3, 0x\2, 0x\1, /'
260 done
261 done <<EOT
262 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
263 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
264 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
265 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
266 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
267 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
268 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
269 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
270 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
271 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
272 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
273 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
274 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
275 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
276 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
277 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391,
278 EOT
279 cat <<EOT
280 /* static const char P_array[64] */
281 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 1 */
282 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, /* 2 */
283 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, /* 3 */
284 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9, /* 4 */
285 /* static const char S_array[16] */
286 7, 12, 17, 22,
287 5, 9, 14, 20,
288 4, 11, 16, 23,
289 6, 10, 15, 21,
290 EOT
292 for mode in data offset ; do
293 ofs=0
294 while read tag str; do
295 if [ "$mode" == "data" ]; then
296 echo -en "$str\0" | hexdump -v -e '" " 16/1 "0x%02X, "' \
297 -e '" // %04.4_ax |" 16/1 "%_p" "| \n"' | \
298 sed 's/ 0x ,/ /g'
299 else
300 if [ $ofs -eq 0 ]; then
301 cat <<EOT
302 };
303 #else
304 static char *$name;
305 #endif
307 #define C_array (uint32_t *) ($name + $(($BOOTISOSZ)))
308 #define P_array (char *) ($name + $(($BOOTISOSZ+(64*4))))
309 #define S_array (char *) ($name + $(($BOOTISOSZ+(64*4)+64)))
310 #define ELTORITOOFS 3
311 EOT
312 fi
313 echo "#define $tag $(($BOOTISOSZ+(64*4)+64+16+$ofs))"
314 ofs=$(($(echo -en "$str\0" | wc -c)+$ofs))
315 fi
316 done <<EOT
317 READSECTORERR Read sector failure.
318 USAGE Usage: isohybrid.exe [--list|--read] [--append cmdline] [--initrd file] file.iso [--forced|--undo|--quick|filename...]
319 OPENERR Can't open r/w the iso file.
320 ELTORITOERR No EL TORITO SPECIFICATION signature.
321 CATALOGERR Invalid boot catalog.
322 HYBRIDERR No isolinux.bin hybrid signature.
323 SUCCESSMSG Now you can create a USB key with your .iso file.\\\\nSimply rename it to an .exe file and run it.
324 FORCEMSG You can add --forced to proceed anyway.
325 MD5MSG Computing md5sum...
326 UNINSTALLMSG Uninstall done.
327 OPENINITRDERR Can't open the initrd file.
328 ALREADYEXEERR Already an EXE file.
329 WIN32_EXE win32.exe
330 SYSLINUX_MBR syslinux.mbr
331 FLAVOR_INFO flavor.info
332 FLOPPY_BOOT floppy.boot
333 TAZBOOT_COM tazboot.com
334 ROOTFS_GZ rootfs.gz
335 DOSSTUB dosstub
336 BOOT_MD5 boot.md5
337 FS_ISO fs.iso
338 CUSTOM_MAGIC custom.magic
339 CUSTOM_APPEND custom.append
340 CUSTOM_INITRD custom.initrd
341 EOT
342 done
343 rm -rf $DATA
344 exit ;;
345 --exe)
346 # --exe mvcom.bin x.com y.exe > xy.exe
347 cat $4 $3 > /tmp/exe$$
348 S=$(stat -c %s /tmp/exe$$)
349 store 2 $(($S%512)) /tmp/exe$$
350 store 4 $((($S+511)/512)) /tmp/exe$$
351 store 14 -16 /tmp/exe$$
352 store 16 -2 /tmp/exe$$
353 store 20 256 /tmp/exe$$
354 store 22 -16 /tmp/exe$$
355 ddq if=$2 bs=1 seek=64 of=/tmp/exe$$ conv=notrunc
356 store 65 $(stat -c %s $3) /tmp/exe$$
357 store 68 $((0x100-0x40+$(stat -c %s $4))) /tmp/exe$$
358 cat /tmp/exe$$
359 rm -f /tmp/exe$$
360 exit ;;
361 esac
363 main()
364 {
365 [ $(id -u) -ne 0 ] && cmd="$0 $@" && exec su -c "$cmd" < /dev/tty
366 append=
367 initrd=
368 while [ "$1" ]; do
369 case "${1/--/-}" in
370 -get) shift
371 uudecode | unlzma | tar xOf - $@
372 exit ;;
373 -a*) append="$2" ; shift 2 ;;
374 -i*) initrd="$2" ; shift 2 ;;
375 -r*|-l*)
376 ISO="$2" ; shift 2
377 [ -z "$1" ] && list || extract $@
378 exit ;;
379 *) cat > /dev/null
380 break
381 esac
382 done
384 [ ! -s "$1" ] && cat 1>&2 <<EOT && exit 1
385 usage: $0 [--list|--read] [--append custom_cmdline ] [ --initrd custom_initrd ] image.iso [--force|--undo|"DOS help message"|filename...]
386 EOT
387 case "${2/--/-}" in
388 -u*|-r*|-w*|-f*)
389 case "$(get 0 $1)" in
390 23117)
391 b=$(get 417 $1 1)
392 n=$(($(get 64 $1) + 0xC0 - ($(get 26 $1 1)*512) - ($b+1)*512))
393 ddq if=$1 bs=512 count=1 skip=$b of=$1 conv=notrunc
394 ddq if=/dev/zero bs=512 seek=1 count=1 of=$1 conv=notrunc
395 ddq if=$1 bs=512 seek=2 count=30 skip=$(($b+1)) of=$1 conv=notrunc
396 ddq if=/dev/zero bs=1 seek=$n count=$((0x8000 - $n)) of=$1 conv=notrunc ;;
397 *) ddq if=/dev/zero bs=1k count=32 of=$1 conv=notrunc ;;
398 esac
399 case "${2/--/-}" in
400 -f*)
401 [ "$append$initrd" ] && clear_custom_config $1 ;;
402 *)
403 clear_custom_config $1
404 exit 0 ;;
405 esac
406 esac
407 case "$(get 0 $1)" in
408 23117) echo "The file $1 is already an EXE file." 1>&2 && exit 1;;
409 0) [ -x /usr/bin/isohybrid ] && isohybrid $1;;
410 esac
412 echo "Read hybrid & tazlito data..."
413 ddq if=$1 bs=512 count=1 of=/tmp/hybrid$$
414 ddq if=$1 bs=512 skip=2 count=20 of=/tmp/tazlito$$
415 add_win32exe $1 /tmp/hybrid$$
416 add_tazlito_info $1 /tmp/tazlito$$
417 rm -f /tmp/tazlito$$ /tmp/hybrid$$
419 # keep the largest room for the tazlito info file
420 add_dosexe $1
421 add_rootfs $1
422 add_doscom $1
423 add_fdbootstrap $1
424 printf "%d free bytes in %04X..%04X\n" $(($OFS-$HOLE)) $HOLE $OFS
425 store 440 $(date +%s) $1 32
426 [ "$2" ] && echo "$2 " | \
427 ddq bs=1 seek=$((0x7FDE)) count=15 conv=notrunc of=$1
428 if [ $(stat -c %s $1) -gt 34816 ]; then
429 echo "Adding ISO image md5 at 7FF0 (16 bytes) ..."
430 echo -en "$(ddq if=$1 bs=2k skip=16 count=$(get 32848 $1 4) | \
431 md5sum | cut -c-32 | sed 's/\(..\)/\\x\1/g')" | \
432 ddq bs=16 seek=2047 conv=notrunc of=$1
433 fi
434 echo -n "Adding boot checksum..."
435 if [ $(stat -c %s $1) -gt 32768 ]; then
436 n=$(($(get 2 $1) - 1 + ($(get 4 $1) - 1)*512))
437 n=$(($(od -v -N $n -t u2 -w2 -An $1 | \
438 awk '{ i+= $0 } END { print (i % 65536) }') \
439 + $(get $(($n+1)) $1 1)))
440 store 18 $(( (-$n -1) % 65536 )) $1
441 fi
442 echo " done."
443 if [ "$append$initrd" ]; then
444 echo -n "Adding custom config... "
445 DATA=/tmp/$(basename $0)$$
446 rm -f $DATA > /dev/null
447 isosz=$(stat -c %s $1)
448 [ "$append" ] && echo "append=$append" >> $DATA
449 [ -s "$initrd" ] && echo "initrd:$(stat -c %s $initrd)" >> $DATA &&
450 cat $initrd >> $DATA
451 echo "#!boot $(md5sum $DATA | sed 's/ .*//')" | cat - $DATA | \
452 ddq bs=2k seek=$(custom_config_sector $1) of=$1 conv=notrunc
453 if [ $(stat -c %s $1) -gt $isosz ]; then
454 echo "$(($(stat -c %s $1) - $isosz)) extra bytes."
455 else
456 echo "$(($isosz - 32768 - 2048*$(get 32848 $1 4)
457 - $(stat -c %s $DATA) - 24)) bytes free."
458 fi
459 rm -f $DATA > /dev/null
460 fi
461 }
463 main "$@" <<EOT