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

syslinux/iso2exe.sh: -f should keep flavor info
author Pascal Bellard <pascal.bellard@slitaz.org>
date Sat Jan 16 10:28:02 2016 +0100 (2016-01-16)
parents 49be2e5503d0
children 7efba77f8483
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 fileofs()
129 {
130 [ $(get 1024 $ISO) -eq 35615 ] && i=1024 || i=$((512*(1+$(get 417 $ISO 1))))
131 stub=$(($(get 20 $ISO) - 0xC0))
132 SIZE=0; OFFSET=0
133 case "$1" in
134 win32.exe) [ $i -eq 1024 ] || SIZE=$(($i - 512));;
135 syslinux.mbr) [ $i -eq 1024 ] || OFFSET=$(($i - 512)); SIZE=512;;
136 flavor.info) OFFSET=$i; SIZE=-1;;
137 floppy.boot) SIZE=$(($(get 26 $ISO 1)*512))
138 OFFSET=$(($(get 64 $ISO) - 0xC0 - $SIZE));;
139 rootfs.gz) SIZE=$(get 24 $ISO); OFFSET=$(($stub - $SIZE));;
140 tazboot.com) OFFSET=$(($(get 64 $ISO) - 0xC0))
141 SIZE=$(($stub - $(get 24 $ISO) - $OFFSET));;
142 dosstub) OFFSET=$stub; SIZE=$((0x8000 - $OFFSET));;
143 md5) OFFSET=$((0x7FF0)); SIZE=16;;
144 esac
145 }
147 list()
148 {
149 for f in win32.exe syslinux.mbr flavor.info floppy.boot \
150 dosstub rootfs.gz tazboot.com md5 ; do
151 fileofs $f
152 [ $SIZE -eq 0 ] && continue
153 [ -n "${OFFSET:6}" ] && continue
154 [ $OFFSET -lt 0 ] && continue
155 [ $(get $OFFSET $ISO 2) -eq 0 ] && continue
156 echo -n "$f at $(printf "%X\n" $OFFSET)"
157 [ $SIZE -eq -1 ] || echo -n " ($SIZE bytes)"
158 echo .
159 done
160 }
162 extract()
163 {
164 for f in $@; do
165 fileofs $f
166 case "$SIZE" in
167 0) ;;
168 -1) ddq bs=1 count=20480 skip=$OFFSET if="$ISO" | zcat >$f ;;
169 *) ddq bs=1 count=$SIZE skip=$OFFSET if="$ISO" >$f ;;
170 esac
171 done
172 }
174 custom_config_sector()
175 {
176 echo $(($(get 32848 "$1" 4)+16))
177 }
179 clear_custom_config()
180 {
181 start=$(custom_config_sector $1)
182 cnt=$((512 - ($start % 512)))
183 [ $cnt -ne 512 ] &&
184 ddq if=/dev/zero of=$1 bs=2k seek=$start count=$cnt
185 }
187 extract_custom_config()
188 {
189 ISO="$1"
190 header=
191 ddq bs=2k skip=$(custom_config_sector "$ISO") if="$ISO" | \
192 while read line; do
193 case "$line" in
194 \#!boot*) header=1 ;;
195 append=*) [ "$header" ] &&
196 echo "${line#append=}" > "$ISO.append" &&
197 ls -l "$ISO.append" ;;
198 initrd:*) [ "$header" ] &&
199 ddq bs=1 count=${line#initrd:} > "$ISO.initrd" &&
200 ls -l "$ISO.initrd" ;;
201 esac
202 [ "$header" ] || break
203 done
204 }
205 case "$1" in
206 --build)
207 shift
208 ls -l $@
209 cat >> $0 <<EOM
210 $(tar cf - $@ | compress | uuencode -m -)
211 EOT
212 EOM
213 sed -i '/^case/,/^esac/d' $0
214 exit ;;
215 --get)
216 cat $2
217 exit ;;
218 --array)
219 DATA=/tmp/dataiso$$
220 ddq if=/dev/zero bs=32k count=1 of=$DATA
221 add_win32exe $DATA $2 > /dev/null
222 HSZ=$OFS
223 add_dosexe $DATA > /dev/null
224 add_rootfs $DATA > /dev/null
225 add_doscom $DATA > /dev/null
226 add_fdbootstrap $DATA > /dev/null
227 name=${3:-bootiso}
228 BOOTISOSZ=$((0x8000 - $OFS + $HSZ))
229 cat <<EOT
231 #define $(echo $name | tr '[a-z]' '[A-Z]')SZ $BOOTISOSZ
233 #ifndef __MSDOS__
234 static char $name[] = {
235 /* head */
236 $(hexdump -v -n $HSZ -e '" " 16/1 "0x%02X, "' -e '" // %04.4_ax |" 16/1 "%_p" "| \n"' $DATA | sed 's/ 0x ,/ /g')
237 /* tail */
238 $(hexdump -v -s $OFS -e '" " 16/1 "0x%02X, "' -e '" // %04.4_ax |" 16/1 "%_p" "| \n"' $DATA | sed 's/ 0x ,/ /g')
240 /* These strange constants are defined in RFC 1321 as
241 T[i] = (int)(4294967296.0 * fabs(sin(i))), i=1..64
242 */
243 /* static const uint32_t C_array[64] */
244 EOT
245 while read a b c d; do
246 for i in $a $b $c $d; do
247 echo $i | sed 's/0x\(..\)\(..\)\(..\)\(..\),/0x\4, 0x\3, 0x\2, 0x\1, /'
248 done
249 done <<EOT
250 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
251 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
252 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
253 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
254 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
255 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
256 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
257 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
258 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
259 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
260 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
261 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
262 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
263 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
264 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
265 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391,
266 EOT
267 cat <<EOT
268 /* static const char P_array[64] */
269 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 1 */
270 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, /* 2 */
271 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, /* 3 */
272 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9, /* 4 */
273 /* static const char S_array[16] */
274 7, 12, 17, 22,
275 5, 9, 14, 20,
276 4, 11, 16, 23,
277 6, 10, 15, 21,
278 EOT
280 for mode in data offset ; do
281 ofs=0
282 while read tag str; do
283 if [ "$mode" == "data" ]; then
284 echo -en "$str\0" | hexdump -v -e '" " 16/1 "0x%02X, "' \
285 -e '" // %04.4_ax |" 16/1 "%_p" "| \n"' | \
286 sed 's/ 0x ,/ /g'
287 else
288 if [ $ofs -eq 0 ]; then
289 cat <<EOT
290 };
291 #else
292 static char *$name;
293 #endif
295 #define C_array (uint32_t *) ($name + $(($BOOTISOSZ)))
296 #define P_array (char *) ($name + $(($BOOTISOSZ+(64*4))))
297 #define S_array (char *) ($name + $(($BOOTISOSZ+(64*4)+64)))
298 #define ELTORITOOFS 3
299 EOT
300 fi
301 echo "#define $tag $(($BOOTISOSZ+(64*4)+64+16+$ofs))"
302 ofs=$(($(echo -en "$str\0" | wc -c)+$ofs))
303 fi
304 done <<EOT
305 READSECTORERR Read sector failure.
306 USAGE Usage: isohybrid.exe [--append cmdline] [--initrd file] file.iso [--forced|--undo|--quick]
307 OPENERR Can't open r/w the iso file.
308 ELTORITOERR No EL TORITO SPECIFICATION signature.
309 CATALOGERR Invalid boot catalog.
310 HYBRIDERR No isolinux.bin hybrid signature.
311 SUCCESSMSG Now you can create a USB key with your .iso file.\\\\nSimply rename it to an .exe file and run it.
312 FORCEMSG You can add --forced to proceed anyway.
313 MD5MSG Computing md5sum...
314 UNINSTALLMSG Uninstall done.
315 OPENINITRDERR Can't open the initrd file.
316 ALREADYEXEERR Already an EXE file.
317 EOT
318 done
319 rm -rf $DATA
320 exit ;;
321 --exe)
322 # --exe mvcom.bin x.com y.exe > xy.exe
323 cat $4 $3 > /tmp/exe$$
324 S=$(stat -c %s /tmp/exe$$)
325 store 2 $(($S%512)) /tmp/exe$$
326 store 4 $((($S+511)/512)) /tmp/exe$$
327 store 14 -16 /tmp/exe$$
328 store 16 -2 /tmp/exe$$
329 store 20 256 /tmp/exe$$
330 store 22 -16 /tmp/exe$$
331 ddq if=$2 bs=1 seek=64 of=/tmp/exe$$ conv=notrunc
332 store 65 $(stat -c %s $3) /tmp/exe$$
333 store 68 $((0x100-0x40+$(stat -c %s $4))) /tmp/exe$$
334 cat /tmp/exe$$
335 rm -f /tmp/exe$$
336 exit ;;
337 esac
339 main()
340 {
341 [ $(id -u) -ne 0 ] && cmd="$0 $@" && exec su -c "$cmd" < /dev/tty
342 append=
343 initrd=
344 while [ "$1" ]; do
345 case "${1/--/-}" in
346 -get) shift
347 uudecode | unlzma | tar xOf - $@
348 exit ;;
349 -a*) append="$2" ; shift 2 ;;
350 -i*) initrd="$2" ; shift 2 ;;
351 -e*) extract_custom_config "$2"
352 exit ;;
353 -r*) ISO="$2" ; shift 2
354 [ -z "$1" ] && list || extract $@
355 exit ;;
356 *) cat > /dev/null
357 break
358 esac
359 done
361 [ ! -s "$1" ] && cat 1>&2 <<EOT && exit 1
362 usage: $0 [--append custom_cmdline ] [ --initrd custom_initramfs ] image.iso [--force|--undo|"DOS help message"]
363 or: $0 --extract-custom-config image.iso
364 EOT
365 case "${2/--/-}" in
366 -u*|-r*|-w*|-f*)
367 case "$(get 0 $1)" in
368 23117)
369 b=$(get 417 $1 1)
370 n=$(($(get 64 $1) + 0xC0 - ($(get 26 $1 1)*512) - ($b+1)*512))
371 ddq if=$1 bs=512 count=1 skip=$b of=$1 conv=notrunc
372 ddq if=/dev/zero bs=512 seek=1 count=1 of=$1 conv=notrunc
373 ddq if=$1 bs=512 seek=2 count=30 skip=$(($b+1)) of=$1 conv=notrunc
374 ddq if=/dev/zero bs=1 seek=$n count=$((0x8000 - $n)) of=$1 conv=notrunc ;;
375 *) ddq if=/dev/zero bs=1k count=32 of=$1 conv=notrunc ;;
376 esac
377 case "${2/--/-}" in
378 -f*)
379 [ "$append$initrd" ] && clear_custom_config $1 ;;
380 *)
381 clear_custom_config $1
382 exit 0 ;;
383 esac
384 esac
385 case "$(get 0 $1)" in
386 23117) echo "The file $1 is already an EXE file." 1>&2 && exit 1;;
387 0) [ -x /usr/bin/isohybrid ] && isohybrid $1;;
388 esac
390 echo "Read hybrid & tazlito data..."
391 ddq if=$1 bs=512 count=1 of=/tmp/hybrid$$
392 ddq if=$1 bs=512 skip=2 count=20 of=/tmp/tazlito$$
393 add_win32exe $1 /tmp/hybrid$$
394 add_tazlito_info $1 /tmp/tazlito$$
395 rm -f /tmp/tazlito$$ /tmp/hybrid$$
397 # keep the largest room for the tazlito info file
398 add_dosexe $1
399 add_rootfs $1
400 add_doscom $1
401 add_fdbootstrap $1
402 printf "%d free bytes in %04X..%04X\n" $(($OFS-$HOLE)) $HOLE $OFS
403 store 440 $(date +%s) $1 32
404 [ "$2" ] && echo "$2 " | \
405 ddq bs=1 seek=$((0x7FDE)) count=15 conv=notrunc of=$1
406 if [ $(stat -c %s $1) -gt 34816 ]; then
407 echo "Adding ISO image md5 at 7FF0 (16 bytes) ..."
408 echo -en "$(ddq if=$1 bs=2k skip=16 count=$(get 32848 $1 4) | \
409 md5sum | cut -c-32 | sed 's/\(..\)/\\x\1/g')" | \
410 ddq bs=16 seek=2047 conv=notrunc of=$1
411 fi
412 echo -n "Adding boot checksum..."
413 if [ $(stat -c %s $1) -gt 32768 ]; then
414 n=$(($(get 2 $1) - 1 + ($(get 4 $1) - 1)*512))
415 n=$(($(od -v -N $n -t u2 -w2 -An $1 | \
416 awk '{ i+= $0 } END { print (i % 65536) }') \
417 + $(get $(($n+1)) $1 1)))
418 store 18 $(( (-$n -1) % 65536 )) $1
419 fi
420 echo " done."
421 if [ "$append$initrd" ]; then
422 echo -n "Adding custom config... "
423 DATA=/tmp/$(basename $0)$$
424 rm -f $DATA > /dev/null
425 isosz=$(stat -c %s $1)
426 [ "$append" ] && echo "append=$append" >> $DATA
427 [ -s "$initrd" ] && echo "initrd:$(stat -c %s $initrd)" >> $DATA &&
428 cat $initrd >> $DATA
429 echo "#!boot $(md5sum $DATA | sed 's/ .*//')" | cat - $DATA | \
430 ddq bs=2k seek=$(custom_config_sector $1) of=$1 conv=notrunc
431 if [ $(stat -c %s $1) -gt $isosz ]; then
432 echo "$(($(stat -c %s $1) - $isosz)) extra bytes."
433 else
434 echo "$(($isosz - 32768 - 2048*$(get 32848 $1 4)
435 - $(stat -c %s $DATA) - 24)) bytes free."
436 fi
437 rm -f $DATA > /dev/null
438 fi
439 }
441 main "$@" <<EOT