tazlito view tazlito @ rev 474

loram: shrink rootfs.gz
author Pascal Bellard <pascal.bellard@slitaz.org>
date Mon Dec 25 17:16:32 2017 +0100 (2017-12-25)
parents 61761275673e
children fb83501c662e
line source
1 #!/bin/sh
2 # TazLito - SliTaz Live Tool.
3 #
4 # Tazlito is a tool to help generate and configure SliTaz Live CD
5 # ISO images. You can create a custom distro in one command from a list of
6 # packages, extract an existing ISO image to hack it, create a new initramfs
7 # and/or a new ISO. Most commands must be run by root, except the stats
8 # and the configuration file manipulation.
9 #
10 # (C) 2007-2017 SliTaz - GNU General Public License.
11 #
12 # Authors: see the AUTHORS file
13 #
15 VERSION='6.0'
17 . /lib/libtaz.sh
18 # Force to use Busybox cpio and wget
19 alias cpio='busybox cpio'
20 alias wget='busybox wget'
22 # Tazlito configuration variables to be shorter
23 # and to use words rather than numbers.
24 COMMAND="$1"
25 LIST_NAME="$2"
26 TMP_DIR="/tmp/tazlito-$$-$RANDOM"
27 TMP_MNT="/media/tazlito-$$-$RANDOM"
28 TOP_DIR="$(pwd)"
29 INITRAMFS='rootfs.gz'
30 LOCALSTATE='/var/lib/tazpkg'
31 INSTALLED="$LOCALSTATE/installed"
32 CACHE_DIR='/var/cache/tazpkg'
33 MIRROR="$LOCALSTATE/mirror"
34 DEFAULT_MIRROR="http://mirror1.slitaz.org/packages/$(cat /etc/slitaz-release)/"
36 log='/var/log/tazlito.log'
37 if [ $(id -u) -eq 0 ]; then
38 newline > $log
39 fi
42 cleanup() {
43 if [ -d "$TMP_MNT" ]; then
44 umount $TMP_MNT
45 rmdir $TMP_MNT
46 rm -f /boot
47 fi
48 [ -d "$tmp_dir" ] && rm -r "$tmp_dir"
49 [ -d "$flv_dir" ] && rm -r "$flv_dir"
50 }
53 # Report error and finish work
55 die() {
56 emsg "<n>$(longline "$@")<n> " >&2
57 cleanup
58 exit 1
59 }
62 # Run Tazlito module
63 module() {
64 local mod="$1"; shift
65 /usr/libexec/tazlito/$mod $@
66 }
70 # Try to include config file, continue if command is gen-config or exit.
71 # The main config used by default is in /etc/tazlito.
72 # Specific distro config file can be put in a distro tree.
73 for i in /etc/tazlito "$TOP_DIR"; do
74 [ -f "$i/tazlito.conf" ] && CONFIG_FILE="$i/tazlito.conf"
75 done
77 [ -z "$CONFIG_FILE" -a "$COMMAND" != 'gen-config' ] && \
78 die 'Unable to find any configuration file.' \
79 'Please read the docs or run `tazlito gen-config` to get an empty config file.'
81 . $CONFIG_FILE
83 # While Tazpkg is not used the default mirror URL file does not exist
84 # and user can't recharge the list of flavors.
85 [ $(id -u) -eq 0 -a ! -f "$MIRROR" ] && echo "$DEFAULT_MIRROR" > $MIRROR
87 # Set the rootfs and rootcd path with $DISTRO
88 # configuration variable.
89 ROOTFS="$DISTRO/rootfs"
90 ROOTCD="$DISTRO/rootcd"
95 #####################
96 # Tazlito functions #
97 #####################
100 # Print the usage.
102 usage () {
103 [ $(basename $0) == 'tazlito' ] && cat <<EOT
105 SliTaz Live Tool - Version: $(colorize 34 "$VERSION")
107 $(boldify "Usage:") tazlito [command] [list|iso|flavor|compression] [dir|iso]
109 $(boldify "Commands:")
110 EOT
111 optlist "\
112 usage Print this short usage.
113 stats View Tazlito and distro configuration statistics.
114 list-addfiles Simple list of additional files in the rootfs.
115 gen-config Generate a new configuration file for a distro.
116 configure Configure the main config file or a specific tazlito.conf.
117 gen-iso Generate a new ISO from a distro tree.
118 gen-initiso Generate a new initramfs and ISO from the distro tree.
119 list-flavors List all flavors available on the mirror.
120 gen-flavor Generate a new Live CD description.
121 gen-liveflavor Generate a Live CD description from current system.
122 show-flavor Show Live CD description.
123 get-flavor Get a flavor's list of packages (--noup to skip update).
124 upgrade-flavor Update package list to the latest available versions.
125 extract-flavor Extract a *.flavor file into $FLAVORS_REPOSITORY.
126 pack-flavor Pack (and update) a flavor from $FLAVORS_REPOSITORY.
127 iso2flavor Create a flavor file from a SliTaz ISO image.
128 extract-distro Extract an ISO to a directory and rebuild Live CD tree.
129 gen-distro Generate a Live distro and ISO from a list of packages.
130 clean-distro Remove all files generated by gen-distro.
131 check-distro Help to check if distro is ready to release.
132 writeiso Use running system to generate a bootable ISO (with /home).
133 merge Merge multiple rootfs into one ISO.
134 deduplicate Deduplicate files in a tree.
135 repack Recompress rootfs into ISO with maximum ratio.
136 build-loram Generate a Live CD for low-RAM systems.
137 emu-iso Emulate an ISO image with QEMU.
138 burn-iso Burn ISO image to a CD-ROM using Wodim.
139 "
140 }
143 yesorno() {
144 local answer
145 echo -n "$1 (y=yes, n=no) [$2] " >&2
146 case "$DEFAULT_ANSWER" in
147 Y|y) answer="y";;
148 N|n) answer="n";;
149 *)
150 read -t 30 answer
151 [ -z "$answer" ] && answer="$2"
152 [ "$answer" != 'y' -a "$answer" != 'n' ] && answer="$2"
153 ;;
154 esac
155 echo "$answer"
156 }
159 field() {
160 grep "^$1" "$2" | \
161 case "$1" in
162 Desc*) sed 's|^.*: *||';;
163 *) sed 's/.*: \([0-9KMG\.]*\).*/\1/';;
164 esac
165 }
168 todomsg() {
169 echo -e "\\033[70G[ \\033[1;31mTODO\\033[0;39m ]"
170 }
173 # Download a file from this mirror
175 download_from() {
176 local i mirrors="$1"
177 shift
178 for i in $mirrors; do
179 case "$i" in
180 http://*|ftp://*|https://*)
181 wget -c $i$@ && break;;
182 *)
183 cp $i/$1 . && break;;
184 esac
185 done
186 }
189 # Download a file trying all mirrors
191 download() {
192 local i
193 for i in $(cat $MIRROR $LOCALSTATE/undigest/*/mirror 2>/dev/null); do
194 download_from "$i" "$@" && break
195 done
196 }
199 # Execute hooks provided by some packages
201 genisohooks() {
202 local here="$(pwd)"
203 for i in $(ls $ROOTFS/etc/tazlito/*.$1 2>/dev/null); do
204 cd $ROOTFS
205 . $i $ROOTCD
206 done
207 cd "$here"
208 }
211 # Echo the package name if the tazpkg is already installed
213 installed_package_name() {
214 local tazpkg="$1" package VERSION EXTRAVERSION
216 # Try to find package name and version to be able
217 # to repack it from installation
218 # A dash (-) can exist in name *and* in version
219 package=${tazpkg%-*}
220 i=$package
221 while true; do
222 unset VERSION EXTRAVERSION
223 eval $(grep -s ^VERSION= $INSTALLED/$i/receipt)
224 eval $(grep -s ^EXTRAVERSION= $INSTALLED/$i/receipt)
225 if [ "$i-$VERSION$EXTRAVERSION" == "$tazpkg" ]; then
226 echo $i
227 break
228 fi
229 case "$i" in
230 *-*);;
231 *) break;;
232 esac
233 i=${i%-*}
234 done
235 }
238 # Check for the rootfs tree.
240 check_rootfs() {
241 [ -d "$ROOTFS/etc" ] || die 'Unable to find a distro rootfs...'
242 }
245 # Check for the boot dir into the root CD tree.
247 verify_rootcd() {
248 [ -d "$ROOTCD/boot" ] || die 'Unable to find the rootcd boot directory...'
249 }
252 # isolinux.conf doesn't know the kernel version.
253 # We name the kernel image 'bzImage'.
254 # isolinux/syslinux first tries the '64' suffix with a 64bits cpu.
256 make_bzImage_hardlink() {
257 if [ -s ${1:-.}/vmlinuz*slitaz ]; then
258 rm -f ${1:-.}/bzImage 2>/dev/null
259 ln ${1:-.}/vmlinuz*slitaz ${1:-.}/bzImage
260 fi
261 if [ -s ${1:-.}/vmlinuz*slitaz64 ]; then
262 rm -f ${1:-.}/bzImage64 2> /dev/null
263 ln ${1:-.}/vmlinuz*slitaz64 ${1:-.}/bzImage64
264 fi
265 }
268 create_iso() {
269 cd $2
270 deduplicate
272 cat > /tmp/cdsort$$ <<EOT
273 $PWD/boot 100
274 $PWD/boot/bzImage 200
275 $(n=199; ls -r $PWD/boot/rootfs* | while read f; do echo "$f $((n--))"; done)
276 $PWD/boot/isolinux 300
277 $PWD/boot/isolinux/boot.cat 400
278 $PWD/boot/isolinux/isolinux.bin 399
279 EOT
281 action 'Computing md5...'
282 touch boot/isolinux/boot.cat
283 find * -type f ! -name md5sum ! -name 'vmlinuz-*' -exec md5sum {} \; > md5sum
284 status
286 cd - >/dev/null
287 title 'Generating ISO image'
289 _ 'Generating %s' "$1"
290 make_bzImage_hardlink $2/boot
291 uefi="$(cd $2 ; ls boot/isolinux/*efi*img 2> /dev/null)"
292 genisoimage -R -o $1 -hide-rr-moved -sort /tmp/cdsort$$ \
293 -b boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat \
294 -no-emul-boot -boot-load-size 4 -boot-info-table \
295 ${uefi:+-eltorito-alt-boot -efi-boot $uefi -no-emul-boot} \
296 -V "${VOLUM_NAME:-SliTaz}" -p "${PREPARED:-$(id -un)}" \
297 -volset "SliTaz $SLITAZ_VERSION" -input-charset utf-8 \
298 -A "tazlito $VERSION/$(genisoimage --version)" \
299 -copyright README -P "www.slitaz.org" -no-pad $2
300 rm -f /tmp/cdsort$$
301 dd if=/dev/zero bs=2k count=16 >> $1 2> /dev/null
303 mkdir /tmp/mnt$$
304 mount -o loop,ro $1 /tmp/mnt$$
305 for i in boot/isolinux/isolinux.bin boot/isolinux/boot.cat ; do
306 sed -i "s|.* $i|$( cd /tmp/mnt$$ ; md5sum $i)|" $2/md5sum
307 done
308 dd if=$2/md5sum of=$1 conv=notrunc bs=2k \
309 seek=$(stat -m /tmp/mnt$$/md5sum | sed q) 2> /dev/null
310 umount -d /tmp/mnt$$
311 rmdir /tmp/mnt$$
313 if [ -s '/etc/tazlito/info' ]; then
314 if [ $(stat -c %s /etc/tazlito/info) -lt $(( 31*1024 )) ]; then
315 action 'Storing ISO info...'
316 dd if=/etc/tazlito/info bs=1k seek=1 of=$1 conv=notrunc 2>/dev/null
317 status
318 fi
319 fi
321 if [ -x '/usr/bin/isohybrid' ]; then
322 action 'Creating hybrid ISO...'
323 /usr/bin/isohybrid $1 -entry 2 2>/dev/null
324 status
325 fi
327 if [ -x '/usr/bin/iso2exe' ]; then
328 echo 'Creating EXE header...'
329 /usr/bin/iso2exe $1 2>/dev/null
330 fi
331 }
334 # Generate a new ISO image using isolinux.
336 gen_livecd_isolinux() {
337 # Some packages may want to alter iso
338 genisohooks iso
339 [ ! -f "$ROOTCD/boot/isolinux/isolinux.bin" ] && die 'Unable to find isolinux binary.'
341 # Set date for boot msg.
342 if grep -q 'XXXXXXXX' "$ROOTCD/boot/isolinux/isolinux.cfg"; then
343 DATE=$(date +%Y%m%d)
344 action 'Setting build date to: %s...' "$DATE"
345 sed -i "s/XXXXXXXX/$DATE/" "$ROOTCD/boot/isolinux/isolinux.cfg"
346 status
347 fi
349 cd $DISTRO
350 create_iso $ISO_NAME.iso $ROOTCD
352 action 'Creating the ISO md5sum...'
353 md5sum $ISO_NAME.iso > $ISO_NAME.md5
354 status
356 separator
357 # Some packages may want to alter final iso
358 genisohooks final
359 }
362 lzma_history_bits() {
363 #
364 # This generates an ISO which boots with Qemu but gives
365 # rootfs errors in frugal or liveUSB mode.
366 #
367 # local n
368 # local sz
369 # n=20 # 1Mb
370 # sz=$(du -sk $1 | cut -f1)
371 # while [ $sz -gt 1024 -a $n -lt 28 ]; do
372 # n=$(( $n + 1 ))
373 # sz=$(( $sz / 2 ))
374 # done
375 # echo $n
376 echo ${LZMA_HISTORY_BITS:-24}
377 }
380 lzma_switches() {
381 local proc_num=$(grep -sc '^processor' /proc/cpuinfo)
382 echo "-d$(lzma_history_bits $1) -mt${proc_num:-1} -mc1000"
383 }
386 lzma_set_size() {
387 # Update size field for lzma'd file packed using -si switch
388 return # Need to fix kernel code?
390 local n i
391 n=$(unlzma < $1 | wc -c)
392 for i in $(seq 1 8); do
393 printf '\\\\x%02X' $(($n & 255))
394 n=$(($n >> 8))
395 done | xargs echo -en | dd of=$1 conv=notrunc bs=1 seek=5 2>/dev/null
396 }
399 align_to_32bits() {
400 local size=$(stat -c %s ${1:-/dev/null})
401 [ $((${size:-0} & 3)) -ne 0 ] &&
402 dd if=/dev/zero bs=1 count=$((4 - ($size & 3))) >> $1 2>/dev/null
403 }
406 dogzip() {
407 gzip -9 > $1
408 [ -x /usr/bin/advdef ] && advdef -qz4 $1
409 }
412 # Pack rootfs
414 pack_rootfs() {
415 ( cd $1; find . -print | cpio -o -H newc ) | \
416 case "$COMPRESSION" in
417 none)
418 _ 'Creating %s without compression...' 'initramfs'
419 cat > $2
420 ;;
421 gzip)
422 _ 'Creating %s with gzip compression...' 'initramfs'
423 dogzip $2
424 ;;
425 *)
426 _ 'Creating %s with lzma compression...' 'initramfs'
427 lzma e -si -so $(lzma_switches $1) > $2
428 lzma_set_size $2
429 ;;
430 esac
431 align_to_32bits $2
432 echo 1 > /tmp/rootfs
433 }
436 # Compression functions for writeiso.
438 write_initramfs() {
439 case "$COMPRESSION" in
440 lzma)
441 _n 'Creating %s with lzma compression...' "$INITRAMFS"
442 cpio -o -H newc | lzma e -si -so $(lzma_switches) > "/$INITRAMFS"
443 align='y'
444 lzma_set_size "/$INITRAMFS"
445 ;;
446 gzip)
447 _ 'Creating %s with gzip compression...' "$INITRAMFS"
448 cpio -o -H newc | dogzip "/$INITRAMFS"
449 ;;
450 *)
451 # align='y'
452 _ 'Creating %s without compression...' "$INITRAMFS"
453 cpio -o -H newc > "/$INITRAMFS"
454 ;;
455 esac < /tmp/list
456 [ "$align" == 'y' -a -z "$noalign" ] && align_to_32bits "/$INITRAMFS"
457 echo 1 > /tmp/rootfs
458 }
461 # Deduplicate files (MUST be on the same filesystem).
463 deduplicate() {
464 find "${@:-.}" -type f -size +0c -xdev -exec stat -c '%s-%a-%u-%g %i %h %n' {} \; | sort | \
465 (
466 save=0; hardlinks=0; old_attr=""; old_inode=""; old_link=""; old_file=""
467 while read attr inode link file; do
468 [ -L "$file" ] && continue
469 if [ "$attr" == "$old_attr" -a "$inode" != "$old_inode" ]; then
470 if cmp "$file" "$old_file" >/dev/null 2>&1 ; then
471 rm -f "$file"
472 if ln "$old_file" "$file" 2>/dev/null; then
473 inode="$old_inode"
474 [ "$link" -eq 1 ] && hardlinks=$(($hardlinks+1)) &&
475 save="$(($save+(${attr%%-*}+512)/1024))"
476 else
477 cp -a "$old_file" "$file"
478 fi
479 fi
480 fi
481 old_attr="$attr" ; old_inode="$inode" ; old_file="$file"
482 done
483 _ '%s Kbytes saved in %s duplicate files.' "$save" "$hardlinks"
484 )
486 find "$@" -type l -xdev -exec stat -c '%s-%u-%g-TARGET- %i %h %n' {} \; | sort | \
487 (
488 old_attr=""; hardlinks=0;
489 while read attr inode link file; do
490 attr="${attr/-TARGET-/-$(readlink $file)}"
491 if [ "$attr" == "$old_attr" ]; then
492 if [ "$inode" != "$old_inode" ]; then
493 rm -f "$file"
494 if ln "$old_file" "$file" 2>/dev/null; then
495 [ "$link" -eq 1 ] && hardlinks=$(($hardlinks+1))
496 else
497 cp -a "$old_file" "$file"
498 fi
499 fi
500 else
501 old_file="$file"
502 old_attr="$attr"
503 old_inode="$inode"
504 fi
505 done
506 _ '%s duplicate symlinks.' "$hardlinks"
507 )
508 }
511 # Generate a new initramfs from the root filesystem.
513 gen_initramfs() {
514 # Just in case CTRL+c
515 rm -f $DISTRO/gen
517 # Some packages may want to alter rootfs
518 genisohooks rootfs
519 cd $1
521 # Normalize file time
522 find $1 -newer $1 -exec touch -hr $1 {} \;
524 # Link duplicate files
525 deduplicate
527 # Use lzma if installed. Display rootfs size in realtime.
528 rm -f /tmp/rootfs 2>/dev/null
529 pack_rootfs . $DISTRO/$(basename $1).gz &
530 sleep 2
531 echo -en "\nFilesystem size:"
532 while [ ! -f /tmp/rootfs ]; do
533 sleep 1
534 echo -en "\\033[18G$(du -sh $DISTRO/$(basename $1).gz | awk '{print $1}') "
535 done
536 echo -e "\n"
537 rm -f /tmp/rootfs
538 cd $DISTRO
539 mv $(basename $1).gz $ROOTCD/boot
540 }
543 distro_sizes() {
544 if [ -n "$start_time" ]; then
545 time=$(($(date +%s) - $start_time))
546 sec=$time
547 div=$(( ($time + 30) / 60))
548 [ "$div" -ne 0 ] && min="~ ${div}m"
549 _ 'Build time : %ss %s' "$sec" "$min"
550 fi
551 cat <<EOT
552 Build date : $(date +%Y%m%d)
553 Packages : $(ls -1 $ROOTFS*$INSTALLED/*/receipt | wc -l)
554 Rootfs size : $(du -csh $ROOTFS*/ | awk 'END { print $1 }')
555 Initramfs size : $(du -csh $ROOTCD/boot/rootfs*.gz | awk 'END { print $1 }')
556 ISO image size : $(du -sh $ISO_NAME.iso | awk '{ print $1 }')
557 EOT
558 footer "Image is ready: $ISO_NAME.iso"
559 }
562 # Print ISO and rootfs size.
564 distro_stats() {
565 title 'Distro statistics: %s' "$DISTRO"
566 distro_sizes
567 }
570 # Create an empty configuration file.
572 empty_config_file() {
573 cat >> tazlito.conf <<"EOF"
574 # tazlito.conf: Tazlito (SliTaz Live Tool) configuration file.
575 #
577 # Name of the ISO image to generate.
578 ISO_NAME=""
580 # ISO image volume name.
581 VOLUM_NAME="SliTaz"
583 # Name of the preparer.
584 PREPARED="$USER"
586 # Path to the packages repository and the packages.list.
587 PACKAGES_REPOSITORY=""
589 # Path to the distro tree to gen-distro from a list of packages.
590 DISTRO=""
592 # Path to the directory containing additional files
593 # to copy into the rootfs and rootcd of the LiveCD.
594 ADDFILES="$DISTRO/addfiles"
596 # Default answer for binary question (Y or N)
597 DEFAULT_ANSWER="ASK"
599 # Compression utility (lzma, gzip or none)
600 COMPRESSION="lzma"
601 EOF
602 }
605 # Extract rootfs.gz somewhere
607 extract_rootfs() {
608 # Detect compression format: *.lzma.cpio, *.gzip.cpio, or *.cpio
609 # First part (lzcat or zcat) may not fail, but cpio will fail on uncorrect format
610 (cd "$2"; lzcat "$1" | cpio -idm --quiet 2>/dev/null) && return
611 (cd "$2"; zcat "$1" | cpio -idm --quiet 2>/dev/null) && return
612 (cd "$2"; cat "$1" | cpio -idm --quiet 2>/dev/null)
613 }
616 # Extract flavor file to temp directory
618 extract_flavor() {
619 # Input: $1 - flavor name to extract;
620 # $2 = absent/empty: just extract 'outer layer'
621 # $2 = 'full': also extract 'inner' rootcd and rootfs archives, make files rename
622 # $2 = 'info': as 'full' and also make 'info' file to put into ISO
623 # Output: temp dir path where flavor was extracted
624 local f="$1.flavor" from to infos="$1.desc"
625 [ -f "$f" ] || die "File '$f' not found"
626 local dir="$(mktemp -d)"
627 zcat "$f" | (cd $dir; cpio -i --quiet >/dev/null)
629 if [ -n "$2" ]; then
630 cd $dir
632 [ -s "$1.receipt" ] && infos="$infos\n$1.receipt"
634 for i in rootcd rootfs; do
635 [ -f "$1.$i" ] || continue
636 mkdir "$i"
637 zcat "$1.$i" | (cd "$i"; cpio -idm --quiet 2>/dev/null)
638 zcat "$1.$i" | cpio -tv 2>/dev/null > "$1.list$i"; infos="$infos\n$1.list$i"
639 rm "$1.$i"
640 done
641 touch -t 197001010100.00 "$1.*"
642 # Info to be stored inside ISO
643 [ "$2" == info ] && echo -e $infos | cpio -o -H newc | dogzip info
644 rm $1.list*
646 # Renames
647 while read from to; do
648 [ -f "$from" ] || continue
649 mv "$from" "$to"
650 done <<EOT
651 $1.nonfree non-free.list
652 $1.pkglist packages.list
653 $1-distro.sh distro.sh
654 $1.receipt receipt
655 $1.mirrors mirrors
656 $1.desc description
657 EOT
658 fi
660 echo $dir
661 }
664 # Pack flavor file from temp directory
666 pack_flavor() {
667 (cd "$1"; ls | grep -v err | cpio -o -H newc) | dogzip "$2.flavor"
668 }
671 # Remove duplicate files
673 files_match() {
674 if [ -d "$1" ]; then
675 return 1
677 elif [ -L "$1" ] && [ -L "$2" ]; then
678 [ "$(readlink "$1")" == "$(readlink "$2")" ] && return 0
680 elif [ -f "$1" ] && [ -f "$2" ]; then
681 cmp -s "$1" "$2" && return 0
683 [ "$(basename "$3")" == 'volatile.cpio.gz' ] &&
684 [ "$(dirname $(dirname "$3"))" == ".$INSTALLED" ] &&
685 return 0
687 elif [ "$(ls -l "$1"|cut -c1-10)$(stat -c '%a:%u:%g:%t:%T' "$1")" == \
688 "$(ls -l "$2"|cut -c1-10)$(stat -c '%a:%u:%g:%t:%T' "$2")" ]; then
689 return 0
691 fi
692 return 1
693 }
695 remove_with_path() {
696 dir="$(dirname $1)"
697 rm -f "$1"
698 while rmdir "$dir" 2> /dev/null; do
699 dir="$(dirname $dir)"
700 done
701 }
703 mergefs() {
704 # Note, many packages have files with spaces in the name
705 IFS=$'\n'
707 local size1=$(du -hs "$1" | awk '{ print $1 }')
708 local size2=$(du -hs "$2" | awk '{ print $1 }')
709 action 'Merge %s (%s) into %s (%s)' "$(basename "$1")" "$size1" "$(basename "$2")" "$size2"
711 # merge symlinks files and devices
712 ( cd "$1"; find ) | \
713 while read file; do
714 files_match "$1/$file" "$2/$file" "$file" &&
715 remove_with_path "$2/$file"
716 done
718 unset IFS
719 status
720 }
723 cleanup_merge() {
724 rm -rf $TMP_DIR
725 exit 1
726 }
729 # Update isolinux config files for multiple rootfs
731 update_bootconfig() {
732 local files
733 action 'Updating boot config files...'
734 files="$(grep -l 'include common' $1/*.cfg)"
735 for file in $files; do
736 awk -v n=$(echo $2 | awk '{ print NF/2 }') '{
737 if (/label/) label=$0;
738 else if (/kernel/) kernel=$0;
739 else if (/append/) {
740 i=index($0,"rootfs.gz");
741 append=substr($0,i+9);
742 }
743 else if (/include/) {
744 for (i = 1; i <= n; i++) {
745 print label i
746 print kernel;
747 initrd="initrd=/boot/rootfs" n ".gz"
748 for (j = n - 1; j >= i; j--) {
749 initrd=initrd ",/boot/rootfs" j ".gz";
750 }
751 printf "\tappend %s%s\n",initrd,append;
752 print "";
753 }
754 print;
755 }
756 else print;
757 }' < $file > $file.$$
758 mv -f $file.$$ $file
759 done
760 sel="$(echo $2 | awk '{
761 for (i=1; i<=NF; i++)
762 if (i % 2 == 0) printf " slitaz%d", i/2
763 else printf " %s", $i
764 }')"
766 [ -s $1/common.cfg ] && cat >> $1/common.cfg <<EOT
768 label slitaz
769 kernel /boot/isolinux/ifmem.c32
770 append$sel noram
772 label noram
773 config noram.cfg
775 EOT
777 # Update vesamenu
778 if [ -s "$1/isolinux.cfg" ]; then
779 files="$files $1/isolinux.cfg"
780 awk -v n=$(echo $2 | awk '{ print NF/2 }') -v "sel=$sel" '
781 BEGIN {
782 kernel = " COM32 c32box.c32"
783 }
784 {
785 if (/ROWS/) print "MENU ROWS " n+$3;
786 else if (/TIMEOUTROW/) print "MENU TIMEOUTROW " n+$3;
787 else if (/TABMSGROW/) print "MENU TABMSGROW " n+$3;
788 else if (/CMDLINEROW/) print "MENU CMDLINEROW " n+$3;
789 else if (/VSHIFT/) {
790 x = $3-n;
791 if (x < 0) x = 0;
792 print "MENU VSHIFT " x;
793 }
794 else if (/rootfs.gz/) {
795 linux = "";
796 if (/bzImage/) linux = "linux /boot/bzImage ";
797 i = index($0, "rootfs.gz");
798 append = substr($0, i+9);
799 printf "\tkernel /boot/isolinux/ifmem.c32\n";
800 printf "\tappend%s noram\n", sel;
801 printf "\nlabel noram\n\tMENU HIDE\n\tconfig noram.cfg\n\n";
802 for (i = 1; i <= n; i++) {
803 print "LABEL slitaz" i
804 printf "\tMENU LABEL SliTaz slitaz%d Live\n", i;
805 printf "%s\n", kernel;
806 initrd = "initrd=/boot/rootfs" n ".gz"
807 for (j = n - 1; j >= i; j--) {
808 initrd = initrd ",/boot/rootfs" j ".gz";
809 }
810 printf "\tappend %s%s%s\n\n", linux, initrd, append;
811 }
812 }
813 else if (/bzImage/) kernel = $0;
814 else print;
815 }' < $1/isolinux.cfg > $1/isolinux.cfg.$$
816 mv $1/isolinux.cfg.$$ $1/isolinux.cfg
817 fi
819 [ -s $1/c32box.c32 ] && sed -i -e '/kernel.*ifmem/d' \
820 -e 's/append \([0-9]\)/append ifmem \1/' $1/isolinux.cfg
821 cat > $1/noram.cfg <<EOT
822 implicit 0
823 prompt 1
824 timeout 80
825 $(grep '^F[0-9]' $1/isolinux.cfg)
827 $([ -s $1/isolinux.msg ] && echo display isolinux.msg)
828 say Not enough RAM to boot slitaz. Trying hacker mode...
829 default hacker
830 label hacker
831 KERNEL /boot/bzImage
832 append rw root=/dev/null vga=normal
834 label reboot
835 EOT
837 if [ -s $1/c32box.c32 ]; then
838 cat >> $1/noram.cfg <<EOT
839 COM32 c32box.c32
840 append reboot
842 label poweroff
843 COM32 c32box.c32
844 append poweroff
846 EOT
847 else
848 echo " com32 reboot.c32" >> $1/noram.cfg
849 fi
851 # Restore real label names
852 [ -s $1/common.cfg ] && files="$1/common.cfg $files"
853 echo $2 | awk '{ for (i=NF; i>1; i-=2) printf "%d/%s\n",i/2,$i }' | \
854 while read pat; do
855 sed -i "s/slitaz$pat/" $files
856 done
857 status
858 }
861 # Uncompress rootfs or module to stdout
863 uncompress() {
864 zcat $1 2> /dev/null || xzcat $1 2> /dev/null ||
865 { [ $(od -N 1 -An $1) -eq 135 ] && unlzma < $1; } || cat $1
866 }
869 # Install a missing package
871 install_package() {
872 if [ -z "$2" ]; then
873 answer=$(yesorno "$(_ 'Install package %s?' "$1")" 'n')
874 else
875 answer=$(yesorno "$(_n 'Install package %s for Kernel %s? ' "$1" "$2")" 'n')
876 fi
877 case "$answer" in
878 y)
879 # We don't want package on host cache.
880 action 'Getting and installing package: %s' "$1"
881 yes y | tazpkg get-install $1 --quiet 2>&1 >> $log || exit 1
882 status ;;
883 *)
884 return 1 ;;
885 esac
886 }
889 # Check iso for loram transformation
891 check_iso_for_loram() {
892 [ -s "$TMP_DIR/iso/boot/rootfs.gz" ] ||
893 [ -s "$TMP_DIR/iso/boot/rootfs1.gz" ]
894 }
897 # Build initial rootfs for loram ISO ram/cdrom/http
899 build_initfs() {
900 urliso="mirror.switch.ch/ftp/mirror/slitaz \
901 download.tuxfamily.org/slitaz mirror1.slitaz.org mirror2.slitaz.org \
902 mirror3.slitaz.org mirror.slitaz.org"
903 version=$(ls $TMP_DIR/iso/boot/vmlinuz-* | sed 's/.*vmlinuz-//')
904 [ -z "$version" ] && die "Can't find the kernel version." \
905 'No file /boot/vmlinuz-<version> in ISO image. Abort.'
907 [ -s /usr/share/boot/busybox-static ] || install_package busybox-static
908 need_lib=false
909 for i in bin dev run mnt proc tmp sys lib/modules; do
910 mkdir -p $TMP_DIR/initfs/$i
911 done
912 ln -s bin $TMP_DIR/initfs/sbin
913 ln -s . $TMP_DIR/initfs/usr
914 for aufs in aufs overlayfs; do
915 [ -f /lib/modules/$version/kernel/fs/$aufs/$aufs.ko.?z ] && break
916 install_package $aufs $version && break
917 done || return 1
918 [ -s /init ] || install_package slitaz-boot-scripts
919 cp /init $TMP_DIR/initfs/
920 cp /lib/modules/$version/kernel/fs/$aufs/$aufs.ko.?z \
921 $TMP_DIR/initfs/lib/modules
922 if [ "$1" == 'cdrom' ]; then
923 sed -i '/mod squashfs/d' $TMP_DIR/initfs/init
924 else
925 [ ! -f /usr/sbin/mksquashfs ] && ! install_package squashfs && return 1
926 while [ ! -f /lib/modules/$version/kernel/fs/squashfs/squashfs.ko.?z ]; do
927 install_package linux-squashfs $version || return 1
928 done
929 cp /lib/modules/$version/kernel/fs/squashfs/squashfs.ko.?z \
930 $TMP_DIR/initfs/lib/modules
931 #ls /sbin/unsquashfs /usr/lib/liblzma.so* $INSTALLED/squashfs/* | \
932 #cpio -o -H newc > $TMP_DIR/initfs/extractfs.cpio
933 fi
934 if [ "$1" == 'http' ]; then
935 mkdir $TMP_DIR/initfs/etc $TMP_DIR/fs
936 ln -s /proc/mounts $TMP_DIR/initfs/etc/mtab
937 cp /usr/share/udhcpc/default.script $TMP_DIR/initfs/lib/udhcpc
938 sed -i 's|/sbin/||;s/^logger/#&/' $TMP_DIR/initfs/lib/udhcpc
939 cp -a /dev/fuse $TMP_DIR/initfs/dev
940 if ! $need_lib && [ -x /usr/share/boot/fusermount-static ]; then
941 cp /usr/share/boot/fusermount-static $TMP_DIR/initfs/bin/fusermount
942 else
943 need_lib=true
944 fi
945 if ! $need_lib && [ -x /usr/share/boot/httpfs-static ]; then
946 cp /usr/share/boot/httpfs-static $TMP_DIR/initfs/bin/httpfs
947 else
948 [ ! -f /usr/bin/httpfs ] && ! install_package httpfs-fuse && return 1
949 cp /usr/bin/httpfs $TMP_DIR/initfs/bin
950 cp /usr/bin/fusermount $TMP_DIR/initfs/bin
951 cp -a /lib/librt* $TMP_DIR/initfs/lib
952 cp -a /lib/libdl* $TMP_DIR/initfs/lib
953 cp -a /lib/libpthread* $TMP_DIR/initfs/lib
954 cp -a /usr/lib/libfuse* $TMP_DIR/initfs/lib
955 cp -a /lib/libresolv* $TMP_DIR/initfs/lib
956 cp -a /lib/libnss_dns* $TMP_DIR/initfs/lib
957 need_lib=true
958 fi
959 cd $TMP_DIR/fs
960 echo 'Getting slitaz-release & ethernet modules...'
961 for i in $(ls -r $TMP_DIR/iso/boot/rootfs*z); do
962 uncompress $i | cpio -idmu etc/slitaz-release lib/modules rootfs*
963 [ -s rootfs* ] || continue
964 unsquashfs -f -d . rootfs* rootfs* etc/slitaz-release lib/modules &&
965 rm -f rootfs*
966 done 2>&1 > /dev/null
967 cd - > /dev/null
968 cp $TMP_DIR/fs/etc/slitaz-release $TMP_DIR/initfs/etc/
969 find $TMP_DIR/fs/lib/modules/*/kernel/drivers/net/ethernet \
970 -type f -name '*.ko*' | while read mod; do
971 f=$TMP_DIR/initfs/lib/modules/$(basename $mod | sed s/..z$//)
972 uncompress $mod > $f
973 grep -q alias=pci: $f || rm -f $f
974 done
975 for i in $TMP_DIR/initfs/lib/modules/*.ko ; do
976 f=$(basename $i)..z
977 grep -q $f:$ $TMP_DIR/fs/lib/modules/*/modules.dep && continue
978 deps="$(grep $f: $TMP_DIR/fs/lib/modules/*/modules.dep | sed 's/.*: //')"
979 echo "$deps" | sed 's|kernel/[^ ]*/||g;s/.ko..z//g' > $TMP_DIR/initfs/lib/modules/$(basename $i .ko).dep
980 for j in $deps; do
981 mod=$(ls $TMP_DIR/fs/lib/modules/*/$j)
982 uncompress $mod > $TMP_DIR/initfs/lib/modules/$(basename $j | sed s/..z$//)
983 done
984 done
985 longline "Default URLs for /iso/$(cat $TMP_DIR/initfs/etc/slitaz-release)/flavors/slitaz-loram-cdrom.iso /iso/$(cat $TMP_DIR/initfs/etc/slitaz-release)/flavors/slitaz-$(cat $TMP_DIR/initfs/etc/slitaz-release)-loram-cdrom.iso: $urliso"
986 _n 'List of URLs to insert: '
987 read -t 30 urliso2
988 urliso="$urliso2 $urliso"
989 fi
990 if ! $need_lib && [ -x /usr/share/boot/busybox-static ]; then
991 cp /usr/share/boot/busybox-static $TMP_DIR/initfs/bin/busybox
992 sed -i 's/LD_T.*ot/newline/;s/".*ld-.*) /"/' $TMP_DIR/initfs/init
993 else
994 cp /bin/busybox $TMP_DIR/initfs/bin
995 if ! cmp /bin/busybox /sbin/insmod > /dev/null ; then
996 cp /sbin/insmod $TMP_DIR/initfs/bin
997 cp -a /lib/libkmod.so.* $TMP_DIR/initfs/lib
998 cp -a /usr/lib/liblzma.so.* $TMP_DIR/initfs/lib
999 cp -a /usr/lib/libz.so.* $TMP_DIR/initfs/lib
1000 fi
1001 need_lib=true
1002 fi
1003 for i in $($TMP_DIR/initfs/bin/busybox | awk \
1004 '{ if (s) printf "%s",$0 } /Currently/ { s=1 }' | sed 's/,//g'); do
1005 ln $TMP_DIR/initfs/bin/busybox $TMP_DIR/initfs/bin/$i
1006 done
1007 # bootfloppybox will need floppy.ko.?z, /dev/fd0, /dev/tty0
1008 cp /lib/modules/$version/kernel/drivers/block/floppy.ko.?z \
1009 $TMP_DIR/initfs/lib/modules 2>/dev/null
1010 for i in /dev/console /dev/null /dev/tty /dev/tty0 /dev/zero \
1011 /dev/kmem /dev/mem /dev/random /dev/urandom; do
1012 cp -a $i $TMP_DIR/initfs/dev
1013 done
1014 grep -q '/sys/block/./dev' $TMP_DIR/initfs/init ||
1015 for i in /dev/fd0 /dev/[hs]d[a-f]* /dev/loop* ; do
1016 cp -a $i $TMP_DIR/initfs/dev
1017 done
1018 $need_lib && for i in /lib/ld-* /lib/lib[cm][-\.]* ; do
1019 cp -a $i $TMP_DIR/initfs/lib
1020 done
1021 [ "$1" == 'http' ] && cat > $TMP_DIR/initfs/init <<EOTEOT
1022 #!/bin/sh
1024 getarg() {
1025 grep -q " \$1=" /proc/cmdline || return 1
1026 eval \$2=\$(sed "s/.* \$1=\\\\([^ ]*\\\\).*/\\\\1/" < /proc/cmdline)
1027 return 0
1030 copy_rootfs() {
1031 total=\$(grep MemTotal /proc/meminfo | sed 's/[^0-9]//g')
1032 need=\$(du -c \${path}rootfs* | tail -n 1 | cut -f1)
1033 [ \$(( \$total / \$need )) -gt 1 ] || return 1
1034 if ! grep -q " keep-loram" /proc/cmdline && cp \${path}rootfs* /mnt; then
1035 path=/mnt/
1036 return 0
1037 else
1038 rm -f /mnt/rootfs*
1039 return 1
1040 fi
1043 echo "Switching / to tmpfs..."
1044 mount -t proc proc /proc
1045 size="\$(grep rootfssize= < /proc/cmdline | \\
1046 sed 's/.*rootfssize=\\([0-9]*[kmg%]\\).*/-o size=\\1/')"
1047 [ -n "\$size" ] || size="-o size=90%"
1049 mount -t sysfs sysfs /sys
1050 for i in /lib/modules/*.ko ; do
1051 echo -en "Probe \$i \\r"
1052 for j in \$(grep alias=pci: \$i | sed 's/alias//;s/\*/.*/g'); do
1053 grep -q "\$j" /sys/bus/pci/devices/*/uevent || continue
1054 for k in \$(cat \${i/ko/dep} 2> /dev/null); do
1055 insmod /lib/modules/\$k.ko 2> /dev/null
1056 done
1057 echo "Loading \$i"
1058 insmod \$i 2> /dev/null
1059 break
1060 done
1061 done
1062 umount /sys
1063 while read var default; do
1064 eval \$var=\$default
1065 getarg \$var \$var
1066 done <<EOT
1067 eth eth0
1068 dns 208.67.222.222,208.67.220.220
1069 netmask 255.255.255.0
1070 gw
1071 ip
1072 EOT
1073 grep -q \$eth /proc/net/dev || sh
1074 if [ -n "\$ip" ]; then
1075 ifconfig \$eth \$ip netmask \$netmask up
1076 route add default gateway \$gw
1077 for i in \$(echo \$dns | sed 's/,/ /g'); do
1078 echo "nameserver \$i" >> /etc/resolv.conf
1079 done
1080 else
1081 udhcpc -f -q -s /lib/udhcpc -i \$eth
1082 fi
1083 for i in $urliso ; do
1084 [ -n "\$URLISO" ] && URLISO="\$URLISO,"
1085 URLISO="\${URLISO}http://\$i/iso/\$(cat /etc/slitaz-release)/flavors/slitaz-loram-cdrom.iso,http://\$i/iso/\$(cat /etc/slitaz-release)/flavors/slitaz-\$(cat /etc/slitaz-release)-loram-cdrom.iso"
1086 URLISO="\$URLISO,http://\$i/iso/rolling/slitaz-rolling-loram-cdrom.iso,http://\$i/iso/rolling/slitaz-rolling-loram.iso"
1087 done
1088 getarg urliso URLISO
1089 DIR=fs
1090 if getarg loram DIR; then
1091 DEVICE=\${DIR%,*}
1092 DIR=/\${DIR#*,}
1093 fi
1094 mount -t tmpfs \$size tmpfs /mnt
1095 path2=/mnt/.httpfs/
1096 path=/mnt/.cdrom/
1097 mkdir -p /mnt/.rw /mnt/.wd \$path \$path2
1098 while [ ! -d \$path/boot ]; do
1099 for i in \$(echo \$URLISO | sed 's/,/ /g'); do
1100 httpfs \$i \$path2 && echo \$i && break
1101 done
1102 mount -o loop,ro -t iso9660 \$path2/*.iso \$path || sh
1103 done
1105 memfree=\$(grep MemFree /proc/meminfo | sed 's/[^0-9]//g')
1106 umount /proc
1107 branch=:/mnt/.cdrom/\$DIR
1108 if [ ! -d /mnt/.cdrom/\$DIR/etc ]; then
1109 branch=
1110 lp=1
1111 insmod /lib/modules/squashfs.ko 2> /dev/null
1112 for i in \${path}boot/rootfs?.* ; do
1113 fs=\${i#*root}
1114 branch=\$branch:/mnt/.\$fs
1115 mkdir -p /mnt/.rw/mnt/.\$fs /mnt/.\$fs /mnt/.rw/mnt/.cdrom
1116 losetup -o 124 /dev/loop\$lp \$i
1117 mount -o loop,ro -t squashfs /dev/loop\$lp /mnt/.\$fs
1118 lp=\$((\$lp+1))
1119 done
1120 fi
1121 mkdir -p /mnt/.rw/mnt/.httpfs
1122 while read type opt; do
1123 insmod /lib/modules/\$type.ko && mount -t \$type -o \$opt none /mnt && break
1124 done <<EOT
1125 aufs br=/mnt/.rw\$branch
1126 overlayfs workdir=/mnt/.wd\${branch/:/,lowerdir=},upperdir=/mnt/.rw
1127 EOT
1128 rm -rf /lib/modules
1129 [ -x /bin/httpfs ] && sed -i 's/DHCP="yes"/DHCP="no"/' /mnt/etc/network.conf
1130 [ \$memfree -lt 30000 ] && sed -i 's/ slim//' /mnt/etc/rcS.conf
1131 [ -x /mnt/sbin/init ] && exec /bin/switch_root mnt /sbin/init || sh
1132 EOTEOT
1133 chmod +x $TMP_DIR/initfs/init
1134 for i in $TMP_DIR/initfs/lib/modules/*z ; do
1135 unxz $i || gunzip $i || lzma d $i ${i%.gz}
1136 rm -f $i
1137 done 2>/dev/null
1138 (cd $TMP_DIR/initfs; find | busybox cpio -o -H newc 2>/dev/null) | \
1139 lzma e $TMP_DIR/initfs.gz -si
1140 lzma_set_size $TMP_DIR/initfs.gz
1141 rm -rf $TMP_DIR/initfs
1142 align_to_32bits $TMP_DIR/initfs.gz
1143 return 0
1147 # Move each initramfs to squashfs
1149 build_loram_rootfs() {
1150 rootfs_sizes=""
1151 for i in $TMP_DIR/iso/boot/rootfs*; do
1152 mkdir -p $TMP_DIR/fs
1153 cd $TMP_DIR/fs
1154 uncompress $i | cpio -idm
1155 deduplicate
1156 cd - > /dev/null
1157 rootfs=$TMP_DIR/$(basename $i)
1158 /usr/sbin/mksquashfs $TMP_DIR/fs $rootfs -comp ${1:-xz -Xbcj x86}
1159 cd $TMP_DIR
1160 rootfs_sizes="$rootfs_sizes $(( $(du -s $TMP_DIR/fs | cut -f1) - $(du -s $rootfs | cut -f1) ))"
1161 ( cd $(dirname $rootfs); echo $(basename $rootfs) | cpio -o -H newc ) > $rootfs.cpio
1162 rm -f $rootfs
1163 mv $rootfs.cpio $rootfs
1164 cd - > /dev/null
1165 rm -rf $TMP_DIR/fs
1166 done
1170 # Move meta boot configuration files to basic configuration files
1171 # because meta loram flavor is useless when rootfs is not loaded in RAM
1173 unmeta_boot() {
1174 local root=${1:-$TMP_DIR/loramiso}
1175 if [ -f $root/boot/isolinux/noram.cfg ]; then
1176 # We keep enough information to do unloram...
1177 [ -s $root/boot/isolinux/common.cfg ] &&
1178 sed -i 's/label slitaz/label orgslitaz/' \
1179 $root/boot/isolinux/common.cfg
1180 set -- $(grep 'append ifmem [0-9]' $root/boot/isolinux/isolinux.cfg)
1181 shift
1182 sed -i '/ifmem/{NNNNNNNNd};/^LABEL/{N;/LABEL SliTaz [^L]/{NNNd}}' \
1183 $root/boot/isolinux/isolinux.cfg
1184 [ -n "$3" ] || set -- $(grep 'append [0-9]' $root/boot/isolinux/common.cfg)
1185 sed -i "s/label $3\$/label slitaz/;s|=\(.*rootfs\)\(.*\)\.gz |=\1.gz |" \
1186 $root/boot/isolinux/*.cfg
1187 fi
1191 # Move rootfs to squashfs filesystem(s) to the cdrom writeable with aufs/overlayfs.
1192 # These squashfs may be loaded in RAM at boot time.
1193 # Rootfs are also copied to CD-ROM for tiny ramsize systems.
1194 # Meta flavors are converted to normal flavors.
1196 build_loram_cdrom() {
1197 build_initfs cdrom || return 1
1198 cp -a $TMP_DIR/iso $TMP_DIR/loramiso
1199 mkdir $TMP_DIR/loramiso/fs
1200 cd $TMP_DIR/loramiso/fs
1201 for i in $( ls ../boot/root* | sort -r ) ; do
1202 uncompress $i | cpio -idmu
1203 rm -f $i
1204 done
1205 mkdir -p $TMP_DIR/loramiso/fs/mnt/.cdrom
1206 cd - >/dev/null
1207 mv $TMP_DIR/initfs.gz $TMP_DIR/loramiso/boot/rootfs.gz
1208 unmeta_boot
1209 VOLUM_NAME="SliTaz_LoRAM_CDROM"
1210 sed -i "s|root=|isofs= rodev=/dev/cdrom/fs &|;s/.ive/cdrom/" \
1211 $TMP_DIR/loramiso/boot/isolinux/*.cfg
1212 sed -i '/LABEL slitaz/{NNNNp;s|z cdrom|& text|;s|L slitaz|&text|;s|root=|screen=text &|;s|,[^ ]*||}' \
1213 $TMP_DIR/loramiso/boot/isolinux/*.cfg
1214 create_iso $OUTPUT $TMP_DIR/loramiso
1218 # Create http bootstrap to load and remove loram_cdrom
1219 # Meta flavors are converted to normal flavors.
1221 build_loram_http() {
1222 build_initfs http || return 1
1223 cp -a $TMP_DIR/iso $TMP_DIR/loramiso
1224 rm -f $TMP_DIR/loramiso/boot/rootfs*
1225 mv $TMP_DIR/initfs.gz $TMP_DIR/loramiso/boot/rootfs.gz
1226 unmeta_boot
1227 create_iso $OUTPUT $TMP_DIR/loramiso
1231 # Update meta flavor selection sizes.
1232 # Reduce sizes with rootfs gains.
1234 update_metaiso_sizes() {
1235 for cfg in $(grep -El '(append|ifmem) [0-9]' $TMP_DIR/loramiso/boot/isolinux/*.cfg)
1236 do
1237 local append="$(grep -E '(append|ifmem) [0-9]' $cfg)"
1238 local sizes="$rootfs_sizes"
1239 local new
1240 set -- $append
1241 shift
1242 [ "$1" == "ifmem" ] && shift
1243 new=""
1244 while [ -n "$2" ]; do
1245 local s
1246 case "$1" in
1247 *G) s=$(( ${1%G} * 1024 * 1024 ));;
1248 *M) s=$(( ${1%M} * 1024 ));;
1249 *) s=${1%K};;
1250 esac
1251 sizes=${sizes#* }
1252 for i in $sizes ; do
1253 s=$(( $s - $i ))
1254 done
1255 new="$new $s $2"
1256 shift 2
1257 done
1258 sed -i -e "/append [0-9]/s/append .*/append$new $1/" -e \
1259 "/append ifmem [0-9]/s/append .*/append ifmem$new $1/" $cfg
1260 sed -i 's|\(initrd=\)\([^r]*\)\(rootfs\)|\1\2rootfs.gz,\2\3|' $cfg
1261 sed -i '/LABEL base/{NNNNp;s|base .ive|cdrom|;s|base|cdrom|;s|,[^ ]*||}' $cfg
1262 sed -i '/LABEL cdrom/{NNNNp;s|z cdrom|& text|;s|L cdrom|&text|;s|root=|screen=text &|;s|,[^ ]*||}' $cfg
1263 done
1267 # Move rootfs to a squashfs filesystem into the initramfs writeable with aufs/overlayfs.
1268 # Meta flavor selection sizes are updated.
1270 build_loram_ram() {
1271 build_initfs ram || return 1
1272 build_loram_rootfs "$1"
1273 cp -a $TMP_DIR/iso $TMP_DIR/loramiso
1274 make_bzImage_hardlink $TMP_DIR/loramiso/boot
1275 mv $TMP_DIR/initfs.gz $TMP_DIR/loramiso/boot/rootfs.gz
1276 cp $TMP_DIR/rootfs* $TMP_DIR/loramiso/boot
1277 update_metaiso_sizes
1278 create_iso $OUTPUT $TMP_DIR/loramiso
1282 # Remove files installed by packages
1284 find_flavor_rootfs() {
1285 for i in $1/etc/tazlito/*.extract; do
1286 [ -e $i ] || continue
1287 chroot $1 /bin/sh ${i#$1}
1288 done
1290 # Clean hardlinks and files patched by genisofs in /boot
1291 for i in isolinux/isolinux.bin isolinux/boot.cat bzImage ; do
1292 rm -f $1/boot/$i*
1293 done
1295 # Clean files generated in post_install
1296 rm -f $1/lib/modules/*/modules.* $1/etc/mtab \
1297 $1/dev/core $1/dev/fd $1/dev/std*
1299 # Verify md5
1300 cat $1$INSTALLED/*/md5sum | \
1301 while read md5 file; do
1302 [ -e "$1$file" ] || continue
1303 [ "$(md5sum < "$1$file")" == "$md5 -" ] &&
1304 rm -f "$1$file"
1305 done
1307 # Check configuration files
1308 for i in $1$INSTALLED/*/volatile.cpio.gz; do
1309 [ -e $i ] || continue
1310 mkdir /tmp/volatile$$
1311 zcat $i | ( cd /tmp/volatile$$ ; cpio -idmu > /dev/null 2>&1 )
1312 ( cd /tmp/volatile$$ ; find * -type f 2> /dev/null) | \
1313 while read file ; do
1314 [ -e "$1/$file" ] || continue
1315 cmp -s "/tmp/volatile$$/$file" "$1/$file" && rm -f "$1/$file"
1316 done
1317 rm -rf /tmp/volatile$$
1318 done
1320 # Remove other files blindly
1321 for i in $1$INSTALLED/*/files.list; do
1322 for file in $(cat "$i"); do
1323 [ "$1$file" -nt "$i" ] && continue
1324 [ -f "$1$file" -a ! -L "$1$file" ] && continue
1325 [ -d "$1$file" ] || rm -f "$1$file"
1326 done
1327 done
1329 # Remove tazpkg files and tmp files
1330 rm -rf $1$INSTALLED* $1/tmp $1/var/tmp
1331 rm -f $1$LOCALSTATE/*packages* $1$LOCALSTATE/files.list.lzma \
1332 $1$LOCALSTATE/mirror* $1/var/cache/*/* \
1333 $1/var/lock/* $1/var/log/* $1/var/run/* $1/var/run/*/* \
1334 $1/var/lib/* $1/var/lib/dbus/* 2>/dev/null
1336 # Cleanup directory tree
1337 cd $1
1338 find * -type d | sort -r | while read dir; do
1339 rmdir "$dir" 2>/dev/null
1340 done
1341 cd - > /dev/null
1345 # Get byte(s) from a binary file
1347 get() {
1348 od -v -j $1 -N ${3:-2} -t u${3:-2} -w${3:-2} -An $2 2>/dev/null
1352 # Get cpio flavor info from the ISO image
1354 flavordata() {
1355 [ $(get 1024 $1) -eq 35615 ] && n=2 || n=$((1+$(get 417 $1 1)))
1356 dd if=$1 bs=512 skip=$n count=20 2>/dev/null | zcat 2>/dev/null
1360 # Restore undigest mirrors
1362 restore_mirrors() {
1363 local undigest="$root$LOCALSTATE/undigest" priority="$root$LOCALSTATE/priority"
1364 [ -d "$undigest.bak" ] || [ -e "$priority.bak" ] || return
1366 action 'Restoring mirrors...'
1367 if [ -d "$undigest.bak" ]; then
1368 [ -d "$undigest" ] && rm -r "$undigest"
1369 mv "$undigest.bak" "$undigest"
1370 fi
1371 [ -e "$priority.bak" ] && mv -f "$priority.bak" "$priority"
1372 :; status
1376 # Setup undigest mirrors
1378 setup_mirrors() {
1379 # Setup mirrors in plain system or in chroot (with variable root=)
1380 local mirrorlist="$1" fresh repacked
1381 local undigest="$root$LOCALSTATE/undigest" priority="$root$LOCALSTATE/priority"
1383 # Restore mirrors first: in case of non-clear exits, hangs, etc.
1384 restore_mirrors
1386 _ 'Setting up mirrors for %s...' "$root/"
1387 # Backing up current undigest mirrors and priority
1388 [ -d "$undigest" ] && mv "$undigest" "$undigest.bak"
1389 [ -e "$priority" ] && mv "$priority" "$priority.bak"
1390 rm -rf '/var/www/tazlito/'
1391 mkdir -p '/var/www/tazlito/'
1393 # Packages produced by CookUtils: on Tank or local, or repacked packages: highest priority
1394 fresh='/home/slitaz/packages'
1395 if [ -d "$fresh" ]; then
1396 # Setup first undigest mirror
1397 mkdir -p "$undigest/fresh"
1398 echo "$fresh" > "$undigest/fresh/mirror"
1399 echo 'fresh' >> "$priority"
1400 # Rebuild mirror DB if needed
1401 [ ! -e "$fresh/IDs" ] && tazpkg mkdb "$fresh" --forced --root=''
1402 [ -n "$(find -L "$fresh" -name '*.tazpkg' -newer "$fresh/IDs")" ] && \
1403 tazpkg mkdb "$fresh" --forced --root=''
1404 cp -a "$fresh/files.list.lzma" "$fresh/files-list.lzma"
1405 fi
1407 # Repacked packages: high priority
1408 repacked="$PACKAGES_REPOSITORY"
1409 if [ -d "$repacked" -a "$repacked" != "$fresh" ] && ls "$repacked" | grep -q ".tazpkg"; then
1410 # According to Tazlito setup file (tazlito.conf):
1411 # WORK_DIR="/home/slitaz/$SLITAZ_VERSION"
1412 # or
1413 # WORK_DIR="/home/slitaz"
1414 # and
1415 # PACKAGES_REPOSITORY="$WORK_DIR/packages"
1416 # It MAY or MAY NOT match /home/slitaz/packages, so here we setup second repository
1418 # Setup second undigest mirror
1419 mkdir -p "$undigest/repacked"
1420 echo "$repacked" > "$undigest/repacked/mirror"
1421 echo 'repacked' >> "$priority"
1422 # Rebuild mirror DB if needed
1423 [ ! -e "$repacked/IDs" ] && tazpkg mkdb "$repacked" --forced --root=''
1424 [ -n "$(find -L "$repacked" -name '*.tazpkg' -newer "$repacked/IDs")" ] && \
1425 tazpkg mkdb "$repacked" --forced --root=''
1426 cp -a "$repacked/files.list.lzma" "$repacked/files-list.lzma"
1427 fi
1429 # All repositories listed in mirrors list: normal priority
1430 [ -e "$mirrorlist" ] && \
1431 while read mirror; do
1432 # Provide consistent mirror ID for caching purpose: /var/cache/tazpkg/<mirror ID>/packages
1433 mirrorid=$(echo "$mirror" | md5sum | cut -d' ' -f1)
1434 mkdir -p "$undigest/$mirrorid"
1435 echo "$mirror" > "$undigest/$mirrorid/mirror"
1436 echo "$mirrorid" >> "$priority"
1437 done < "$mirrorlist"
1439 # And, finally, main mirror with the lowest (failsafe) priority (nothing to do)
1441 # Show list of mirrors
1442 [ -f "$priority" ] && awk -vdb="$root$LOCALSTATE" '
1443 function show(num, name, url) {
1444 printf " %-1.1d. %32.32s %-44.44s\n", num, name " ...............................", url;
1447 num++;
1448 "cat " db "/undigest/" $0 "/mirror" | getline url;
1449 show(num, $0, url);
1451 END {
1452 num++;
1453 "cat " db "/mirror" | getline url;
1454 show(num, "main", url);
1455 }' "$priority"
1457 tazpkg recharge --quiet >/dev/null
1461 # Get list of 'packages.info' lists using priority
1463 pi_lists() {
1464 local pi
1465 [ -s "$root$LOCALSTATE/packages.info" ] || tazpkg recharge --root="$root" >/dev/null 2>&1
1466 local priority="$root$LOCALSTATE/priority"
1467 local undigest="$root$LOCALSTATE/undigest"
1470 [ -s "$priority" ] && cat "$priority"
1471 echo 'main'
1472 [ -d "$undigest" ] && ls "$undigest"
1473 } | awk -vun="$undigest/" '
1475 if (arr[$0] != 1) {
1476 arr[$0] = 1;
1477 print un $0 "/packages.info";
1479 }' | sed 's|/undigest/main||' | \
1480 while read pi; do
1481 [ -e "$pi" ] && echo "$pi"
1482 done
1486 # Strip versions from packages list
1488 strip_versions() {
1489 if [ -n "$stripped" ]; then
1490 action 'Consider list %s already stripped' "$(basename "$1")"
1491 status
1492 return 0
1493 fi
1494 action 'Strip versions from list %s...' "$(basename "$1")"
1495 local in_list="$1" tmp_list="$(mktemp)" namever pkg
1496 [ -f "$in_list" ] || die "List '$in_list' not found."
1498 # $pkg=<name>-<version> or $pkg=<name>; both <name> and <version> may contain dashes
1499 awk '
1501 if (FILENAME ~ "packages.info") {
1502 # Collect package names
1503 FS = "\t"; pkg[$1] = 1;
1504 } else {
1505 FS = OFS = "-"; $0 = $0; # Fix bug with FS for first record
1506 while (NF > 1 && ! pkg[$0])
1507 NF --;
1508 printf "%s\n", $0;
1510 }' $(pi_lists) "$in_list" > "$tmp_list"
1512 cat "$tmp_list" > "$in_list"
1513 rm "$tmp_list"
1514 status
1518 # Display list of unknown packages (informative)
1520 display_unknown() {
1521 [ -s "$1" ] || return
1522 echo "Unknown packages:" >&2
1523 cat "$1" >&2
1524 rm "$1"
1528 # Display warnings about critical packages absent (informative)
1530 display_warn() {
1531 [ -s "$1" ] || return
1532 echo "Absent critical packages:" >&2
1533 cat "$1" >&2
1534 rm "$1"
1535 echo "Probably ISO image will be unusable."
1539 # Install packages to rootfs
1541 install_list_to_rootfs() {
1542 local list="$1" rootfs="$2" pkg i ii
1543 local undigest="$rootfs/var/lib/tazpkg/undigest"
1545 # initial tazpkg setup in empty rootfs
1546 tazpkg --root=$rootfs >/dev/null 2>&1
1547 # pass current 'mirror' to the rootfs
1548 mkdir -p $rootfs/var/lib/tazpkg $rootfs/etc
1549 cp -f /var/lib/tazpkg/mirror $rootfs/var/lib/tazpkg/mirror
1550 cp -f /etc/slitaz-release $rootfs/etc/slitaz-release
1551 # link rootfs packages cache to the regular packages cache
1552 rm -r "$rootfs/var/cache/tazpkg"
1553 ln -s /var/cache/tazpkg "$rootfs/var/cache/tazpkg"
1555 setup_mirrors mirrors
1557 # Just in case if flavor not contains "tazlito" package
1558 mkdir -p "$rootfs/etc/tazlito"
1560 newline
1562 # Choose detailed log with --detailed
1563 if [ -n "$detailed" ]; then
1564 while read pkg; do
1565 separator '-'
1566 echo $pkg
1567 tazpkg -gi $pkg --root=$rootfs --local --quiet --cookmode | tee -a $log
1568 done < $list
1569 separator '='
1570 else
1571 while read pkg; do
1572 action 'Installing package: %s' "$pkg"
1573 yes y | tazpkg -gi $pkg --root=$rootfs --quiet >> $log || exit 1
1574 status
1575 done < $list
1576 fi
1577 newline
1579 restore_mirrors
1580 # Remove 'fresh' and 'repacked' undigest repos leaving all other
1581 for i in fresh repacked; do
1582 ii="$undigest/$i"
1583 [ -d "$ii" ] && rm -rf "$ii"
1584 ii="$rootfs/var/lib/tazpkg/priority"
1585 if [ -f "$ii" ]; then
1586 sed -i "/$i/d" "$ii"
1587 [ -s "$ii" ] || rm "$ii"
1588 fi
1589 done
1590 [ -d "$undigest" ] && \
1591 for i in $(find "$undigest" -type f); do
1592 # Remove all undigest PKGDB files but 'mirror'
1593 [ "$(basename "$i")" != 'mirror' ] && rm "$i"
1594 done
1595 [ -d "$undigest" ] && \
1596 rmdir --ignore-fail-on-non-empty "$undigest"
1598 # Un-link packages cache
1599 rm "$rootfs/var/cache/tazpkg"
1601 # Clean /var/lib/tazpkg
1602 (cd $rootfs/var/lib/tazpkg; rm ID* descriptions.txt extra.list files* packages.* 2>/dev/null)
1608 ####################
1609 # Tazlito commands #
1610 ####################
1612 # /usr/bin/tazlito is linked with /usr/bin/reduplicate and /usr/bin/deduplicate
1613 case "$0" in
1614 *reduplicate)
1615 find ${@:-.} ! -type d -links +1 \
1616 -exec cp -a {} {}$$ \; -exec mv {}$$ {} \;
1617 exit 0 ;;
1618 *deduplicate)
1619 deduplicate "$@"
1620 exit 0 ;;
1621 esac
1624 case "$COMMAND" in
1625 stats)
1626 # Tazlito general statistics from the config file.
1628 title 'Tazlito statistics'
1629 optlist "\
1630 Config file : $CONFIG_FILE
1631 ISO name : $ISO_NAME.iso
1632 Volume name : $VOLUM_NAME
1633 Prepared : $PREPARED
1634 Packages repository : $PACKAGES_REPOSITORY
1635 Distro directory : $DISTRO
1636 Additional files : $ADDFILES
1637 " | sed '/: $/d'
1638 footer
1639 ;;
1642 list-addfiles)
1643 # Simple list of additional files in the rootfs
1644 newline
1645 if [ -d "$ADDFILES/rootfs" ]; then
1646 cd $ADDFILES
1647 find rootfs -type f
1648 else
1649 _ 'Additional files not found: %s' "$ADDFILES/rootfs/"
1650 fi
1651 newline
1652 ;;
1655 gen-config)
1656 # Generate a new config file in the current dir or the specified
1657 # directory by $2.
1659 if [ -n "$2" ]; then
1660 mkdir -p "$2" && cd "$2"
1661 fi
1663 newline
1664 action 'Generating empty tazlito.conf...'
1665 empty_config_file
1666 status
1668 separator
1669 if [ -f 'tazlito.conf' ] ; then
1670 _ 'Configuration file is ready to edit.'
1671 _ 'File location: %s' "$(pwd)/tazlito.conf"
1672 newline
1673 fi
1674 ;;
1677 configure)
1678 # Configure a tazlito.conf config file. Start by getting
1679 # a empty config file and sed it.
1681 if [ -f 'tazlito.conf' ]; then
1682 rm tazlito.conf
1683 else
1684 [ $(id -u) -ne 0 ] && die 'You must be root to configure the main config file' \
1685 'or in the same directory of the file you want to configure.'
1686 cd /etc
1687 fi
1689 empty_config_file
1691 title 'Configuring: %s' "$(pwd)/tazlito.conf"
1693 # ISO name.
1694 echo -n "ISO name : " ; read answer
1695 sed -i s#'ISO_NAME=\"\"'#"ISO_NAME=\"$answer\""# tazlito.conf
1696 # Volume name.
1697 echo -n "Volume name : " ; read answer
1698 sed -i s/'VOLUM_NAME=\"SliTaz\"'/"VOLUM_NAME=\"$answer\""/ tazlito.conf
1699 # Packages repository.
1700 echo -n "Packages repository : " ; read answer
1701 sed -i s#'PACKAGES_REPOSITORY=\"\"'#"PACKAGES_REPOSITORY=\"$answer\""# tazlito.conf
1702 # Distro path.
1703 echo -n "Distro path : " ; read answer
1704 sed -i s#'DISTRO=\"\"'#"DISTRO=\"$answer\""# tazlito.conf
1705 footer "Config file is ready to use."
1706 echo 'You can now extract an ISO or generate a distro.'
1707 newline
1708 ;;
1711 gen-iso)
1712 # Simply generate a new iso.
1714 check_root
1715 verify_rootcd
1716 gen_livecd_isolinux
1717 distro_stats
1718 ;;
1721 gen-initiso)
1722 # Simply generate a new initramfs with a new iso.
1724 check_root
1725 verify_rootcd
1726 gen_initramfs "$ROOTFS"
1727 gen_livecd_isolinux
1728 distro_stats
1729 ;;
1732 extract-distro)
1733 # Extract an ISO image to a directory and rebuild the LiveCD tree.
1735 check_root
1736 ISO_IMAGE="$2"
1737 [ -z "$ISO_IMAGE" ] && die 'Please specify the path to the ISO image.' \
1738 'Example:\n tazlito image.iso /path/target'
1740 # Set the distro path by checking for $3 on cmdline.
1741 TARGET="${3:-$DISTRO}"
1743 # Exit if existing distro is found.
1744 [ -d "$TARGET/rootfs" ] && die "A rootfs exists in '$TARGET'." \
1745 'Please clean the distro tree or change directory path.'
1747 title 'Tazlito extracting: %s' "$(basename $ISO_IMAGE)"
1749 # Start to mount the ISO.
1750 action 'Mounting ISO image...'
1751 mkdir -p "$TMP_DIR"
1752 # Get ISO file size.
1753 isosize=$(du -sh "$ISO_IMAGE" | cut -f1)
1754 mount -o loop -r "$ISO_IMAGE" "$TMP_DIR"
1755 sleep 2
1756 # Prepare target dir, copy the kernel and the rootfs.
1757 mkdir -p "$TARGET/rootfs" "$TARGET/rootcd/boot"
1758 status
1760 action 'Copying the Linux kernel...'
1761 if cp $TMP_DIR/boot/vmlinuz* "$TARGET/rootcd/boot" 2>/dev/null; then
1762 make_bzImage_hardlink "$TARGET/rootcd/boot"
1763 else
1764 cp "$TMP_DIR/boot/bzImage" "$TARGET/rootcd/boot"
1765 fi
1766 status
1768 for i in $(ls $TMP_DIR); do
1769 [ "$i" == 'boot' ] && continue
1770 cp -a "$TMP_DIR/$i" "$TARGET/rootcd"
1771 done
1773 for loader in isolinux syslinux extlinux grub; do
1774 [ -d "$TMP_DIR/boot/$loader" ] || continue
1775 action 'Copying %s files...' "$loader"
1776 cp -a "$TMP_DIR/boot/$loader" "$TARGET/rootcd/boot"
1777 status
1778 done
1780 action 'Copying the rootfs...'
1781 cp $TMP_DIR/boot/rootfs.?z "$TARGET/rootcd/boot"
1782 status
1784 # Extract initramfs.
1785 cd "$TARGET/rootfs"
1786 action 'Extracting the rootfs...'
1787 extract_rootfs "$TARGET/rootcd/boot/$INITRAMFS" "$TARGET/rootfs"
1788 # unpack /usr
1789 for i in etc/tazlito/*.extract; do
1790 [ -f "$i" ] && . $i ../rootcd
1791 done
1792 # Umount and remove temp directory and cd to $TARGET to get stats.
1793 umount "$TMP_DIR" && rm -rf "$TMP_DIR"
1794 cd ..
1795 status
1797 newline
1798 separator
1799 echo "Extracted : $(basename $ISO_IMAGE) ($isosize)"
1800 echo "Distro tree : $(pwd)"
1801 echo "Rootfs size : $(du -sh rootfs)"
1802 echo "Rootcd size : $(du -sh rootcd)"
1803 footer
1804 ;;
1807 list-flavors)
1808 # Show available flavors.
1809 list='/etc/tazlito/flavors.list'
1810 [ ! -s $list -o -n "$recharge" ] && download flavors.list -O - > $list
1811 title 'List of flavors'
1812 cat $list
1813 footer
1814 ;;
1817 show-flavor)
1818 # Show flavor description.
1819 set -e
1820 flavor=${2%.flavor}
1821 flv_dir="$(extract_flavor "$flavor")"
1822 desc="$flv_dir/$flavor.desc"
1823 if [ -n "$brief" ]; then
1824 if [ -z "$noheader" ]; then
1825 printf "%-16.16s %6.6s %6.6s %s\n" 'Name' 'ISO' 'Rootfs' 'Description'
1826 separator
1827 fi
1828 printf "%-16.16s %6.6s %6.6s %s\n" "$flavor" \
1829 "$(field ISO "$desc")" \
1830 "$(field Rootfs "$desc")" \
1831 "$(field Description "$desc")"
1832 else
1833 separator
1834 cat "$desc"
1835 fi
1836 cleanup
1837 ;;
1840 gen-liveflavor)
1841 # Generate a new flavor from the live system.
1842 FLAVOR=${2%.flavor}
1843 [ -z "$FLAVOR" ] && die 'Please specify flavor name on the commandline.'
1845 case "$FLAVOR" in
1846 -?|-h*|--help)
1847 cat <<EOT
1848 SliTaz Live Tool - Version: $VERSION
1850 $(boldify 'Usage:') tazlito gen-liveflavor <flavor-name> [<flavor-patch-file>]
1852 $(boldify '<flavor-patch-file> format:')
1853 $(optlist "\
1854 code data
1855 + package to add
1856 - package to remove
1857 ! non-free package to add
1858 ? display message
1859 @ flavor description
1860 ")
1862 $(boldify 'Example:')
1863 $(optlist "\
1864 @ Developer tools for SliTaz maintainers
1865 + slitaz-toolchain
1866 + mercurial
1867 ")
1868 EOT
1869 exit 1
1870 ;;
1871 esac
1872 mv /etc/tazlito/distro-packages.list \
1873 /etc/tazlito/distro-packages.list.$$ 2>/dev/null
1874 rm -f distro-packages.list non-free.list 2>/dev/null
1875 tazpkg recharge
1877 DESC=""
1878 [ -n "$3" ] && \
1879 while read action pkg; do
1880 case "$action" in
1881 +) yes | tazpkg get-install $pkg 2>&1 >> $log || exit 1 ;;
1882 -) yes | tazpkg remove $pkg ;;
1883 !) echo $pkg >> non-free.list ;;
1884 @) DESC="$pkg" ;;
1885 \?) echo -en "$pkg"; read action ;;
1886 esac
1887 done < $3
1889 yes '' | tazlito gen-distro
1890 echo "$DESC" | tazlito gen-flavor "$FLAVOR"
1891 mv /etc/tazlito/distro-packages.list.$$ \
1892 /etc/tazlito/distro-packages.list 2>/dev/null
1893 ;;
1896 gen-flavor)
1897 # Generate a new flavor from the last ISO image generated
1898 FLAVOR=${2%.flavor}
1899 [ -z "$FLAVOR" ] && die 'Please specify flavor name on the commandline.'
1901 title 'Flavor generation'
1902 check_rootfs
1903 FILES="$FLAVOR.pkglist"
1905 action 'Creating file %s...' "$FLAVOR.flavor"
1906 for i in rootcd rootfs; do
1907 if [ -d "$ADDFILES/$i" ] ; then
1908 FILES="$FILES\n$FLAVOR.$i"
1909 ( cd "$ADDFILES/$i"; find . ) | cpio -o -H newc 2>/dev/null | dogzip $FLAVOR.$i
1910 fi
1911 done
1912 status
1914 answer=$(grep -s ^Description $FLAVOR.desc)
1915 answer=${answer#Description : }
1916 if [ -z "$answer" ]; then
1917 echo -n "Description: "
1918 read answer
1919 fi
1921 action 'Compressing flavor %s...' "$FLAVOR"
1922 echo "Flavor : $FLAVOR" > $FLAVOR.desc
1923 echo "Description : $answer" >> $FLAVOR.desc
1924 (cd $DISTRO; distro_sizes) >> $FLAVOR.desc
1925 \rm -f $FLAVOR.pkglist $FLAVOR.nonfree 2>/dev/null
1926 for i in $(ls $ROOTFS$INSTALLED); do
1927 eval $(grep ^VERSION= $ROOTFS$INSTALLED/$i/receipt)
1928 EXTRAVERSION=""
1929 eval $(grep ^EXTRAVERSION= $ROOTFS$INSTALLED/$i/receipt)
1930 eval $(grep ^CATEGORY= $ROOTFS$INSTALLED/$i/receipt)
1931 if [ "$CATEGORY" == 'non-free' -a "${i%%-*}" != 'get' ]; then
1932 echo "$i" >> $FLAVOR.nonfree
1933 else
1934 echo "$i-$VERSION$EXTRAVERSION" >> $FLAVOR.pkglist
1935 fi
1936 done
1937 [ -s $FLAVOR.nonfree ] && $FILES="$FILES\n$FLAVOR.nonfree"
1938 for i in $LOCALSTATE/undigest/*/mirror ; do
1939 [ -s $i ] && cat $i >> $FLAVOR.mirrors
1940 done
1941 [ -s $FLAVOR.mirrors ] && $FILES="$FILES\n$FLAVOR.mirrors"
1942 touch -t 197001010100.00 $FLAVOR.*
1943 echo -e "$FLAVOR.desc\n$FILES" | cpio -o -H newc 2>/dev/null | dogzip $FLAVOR.flavor
1944 rm $(echo -e $FILES)
1945 status
1947 footer "Flavor size: $(du -sh $FLAVOR.flavor)"
1948 ;;
1951 upgrade-flavor)
1952 # Strip versions from pkglist and update estimated numbers in flavor.desc
1953 flavor="${2%.flavor}"
1954 set -e
1955 [ -f "$flavor.flavor" ] || download "$flavor.flavor"
1956 set +e
1958 flv_dir="$(extract_flavor "$flavor")"
1960 strip_versions "$flv_dir/$flavor.pkglist"
1962 action 'Updating %s...' "$flavor.desc"
1964 [ -f "$flv_dir/$flavor.mirrors" ] && setup_mirrors "$flv_dir/$flavor.mirrors" >/dev/null
1965 set -- $(module calc_sizes "$flv_dir" "$flavor")
1966 restore_mirrors >/dev/null
1968 sed -i -e '/Image is ready/d' \
1969 -e "s|\(Rootfs size *:\).*$|\1 $1 (estimated)|" \
1970 -e "s|\(Initramfs size *:\).*$|\1 $2 (estimated)|" \
1971 -e "s|\(ISO image size *:\).*$|\1 $3 (estimated)|" \
1972 -e "s|\(Packages *:\).*$|\1 $4|" \
1973 -e "s|\(Build date *:\).*$|\1 $(date '+%Y%m%d at %T')|" \
1974 "$flv_dir/$flavor.desc"
1976 pack_flavor "$flv_dir" "$flavor"
1977 status
1978 display_unknown "$flv_dir/err"
1979 display_warn "$flv_dir/warn"
1980 cleanup
1981 ;;
1984 extract-flavor)
1985 # Extract a flavor into $FLAVORS_REPOSITORY
1986 flavor="${2%.flavor}"
1987 set -e
1988 [ -f "$flavor.flavor" ] || download "$flavor.flavor"
1989 set +e
1991 action 'Extracting %s...' "$flavor.flavor"
1992 flv_dir="$(extract_flavor "$flavor" full)"
1993 storage="$FLAVORS_REPOSITORY/$flavor"
1995 rm -rf "$storage" 2>/dev/null
1996 mkdir -p "$storage"
1997 cp -a "$flv_dir"/* "$storage"
1998 rm "$storage/description"
1999 status
2001 strip_versions "$storage/packages.list"
2003 cleanup
2004 ;;
2007 pack-flavor)
2008 # Create a flavor from $FLAVORS_REPOSITORY.
2009 flavor=${2%.flavor}
2010 storage="$FLAVORS_REPOSITORY/$flavor"
2012 [ -s "$storage/receipt" ] || die "No $flavor receipt in $FLAVORS_REPOSITORY."
2014 action 'Creating flavor %s...' "$flavor"
2015 tmp_dir="$(mktemp -d)"
2017 while read from to; do
2018 [ -s "$storage/$from" ] || continue
2019 cp -a "$storage/$from" "$tmp_dir/$to"
2020 done <<EOT
2021 mirrors $flavor.mirrors
2022 distro.sh $flavor-distro.sh
2023 receipt $flavor.receipt
2024 non-free.list $flavor.nonfree
2025 EOT
2027 # Build the package list.
2028 # It can include a list from another flavor with the keyword @include
2029 if [ -s "$storage/packages.list" ]; then
2030 include=$(grep '^@include' "$storage/packages.list")
2031 if [ -n "$include" ]; then
2032 include=${include#@include }
2033 if [ -s "$FLAVORS_REPOSITORY/$include/packages.list" ]; then
2034 cp -f "$FLAVORS_REPOSITORY/$include/packages.list" "$tmp_dir/$flavor.pkglist"
2035 else
2036 echo -e "\nERROR: Can't find include package list from $include\n"
2037 fi
2038 fi
2039 # Generate the final/initial package list
2040 [ -s "$storage/packages.list" ] && \
2041 cat "$storage/packages.list" >> "$tmp_dir/$flavor.pkglist"
2042 sed -i '/@include/d' "$tmp_dir/$flavor.pkglist"
2043 fi
2045 if grep -q ^ROOTFS_SELECTION "$storage/receipt"; then
2046 # Process multi-rootfs flavor
2047 . "$storage/receipt"
2048 set -- $ROOTFS_SELECTION
2049 [ -n "$FRUGAL_RAM" ] || FRUGAL_RAM=$1
2050 [ -f "$FLAVORS_REPOSITORY/$2/packages.list" ] || tazlito extract-flavor $2
2051 cp "$FLAVORS_REPOSITORY/$2/packages.list" "$tmp_dir/$flavor.pkglist"
2053 for i in rootcd rootfs; do
2054 mkdir "$tmp_dir/$i"
2055 # Copy extra files from the first flavor
2056 [ -d "$FLAVORS_REPOSITORY/$2/$i" ] &&
2057 cp -a "$FLAVORS_REPOSITORY/$2/$i" "$tmp_dir"
2058 # Overload extra files by meta flavor
2059 [ -d "$storage/$i" ] && cp -a "$storage/$i" "$tmp_dir"
2060 [ -n "$(ls $tmp_dir/$i)" ] &&
2061 (cd "$tmp_dir/$i"; find . | cpio -o -H newc 2>/dev/null ) | \
2062 dogzip "$tmp_dir/$flavor.$i"
2063 rm -rf "$tmp_dir/$i"
2064 done
2065 else
2066 # Process plain flavor
2067 for i in rootcd rootfs; do
2068 [ -d "$storage/$i" ] || continue
2069 (cd "$storage/$i";
2070 find . | cpio -o -H newc 2>/dev/null) | dogzip "$tmp_dir/$flavor.$i"
2071 done
2072 fi
2074 unset VERSION MAINTAINER ROOTFS_SELECTION
2075 set -- $(module calc_sizes "$tmp_dir" "$flavor")
2076 ROOTFS_SIZE="$1 (estimated)"
2077 INITRAMFS_SIZE="$2 (estimated)"
2078 ISO_SIZE="$3 (estimated)"
2079 PKGNUM="$4"
2080 . "$storage/receipt"
2082 sed '/: $/d' > "$tmp_dir/$flavor.desc" <<EOT
2083 Flavor : $FLAVOR
2084 Description : $SHORT_DESC
2085 Version : $VERSION
2086 Maintainer : $MAINTAINER
2087 LiveCD RAM size : $FRUGAL_RAM
2088 Rootfs list : $ROOTFS_SELECTION
2089 Build date : $(date '+%Y%m%d at %T')
2090 Packages : $PKGNUM
2091 Rootfs size : $ROOTFS_SIZE
2092 Initramfs size : $INITRAMFS_SIZE
2093 ISO image size : $ISO_SIZE
2094 ================================================================================
2096 EOT
2098 rm -f $tmp_dir/packages.list
2099 pack_flavor "$tmp_dir" "$flavor"
2100 status
2101 display_unknown "$tmp_dir/err"
2102 display_warn "$flv_dir/warn"
2103 cleanup
2104 ;;
2107 get-flavor)
2108 # Get a flavor's files and prepare for gen-distro.
2109 flavor=${2%.flavor}
2110 title 'Preparing %s distro flavor' "$flavor"
2111 set -e
2112 [ -f "$flavor.flavor" ] || download "$flavor.flavor"
2113 set +e
2115 action 'Cleaning %s...' "$DISTRO"
2116 [ -d "$DISTRO" ] && rm -r "$DISTRO"
2117 # Clean old files
2118 for i in non-free.list distro-packages.list distro.sh receipt mirrors err; do
2119 [ -f "$i" ] && rm "$i"
2120 done
2121 mkdir -p "$DISTRO"
2122 status
2124 [ -z "$noup" ] && tazlito upgrade-flavor "$flavor.flavor"
2126 action 'Extracting flavor %s...' "$flavor.flavor"
2127 flv_dir="$(extract_flavor "$flavor" info)"
2128 cp -a "$flv_dir"/* .
2129 mv packages.list distro-packages.list
2130 mv -f info /etc/tazlito
2131 status
2133 for i in rootcd rootfs; do
2134 if [ -d "$i" ]; then
2135 mkdir -p "$ADDFILES"; mv "$i" "$ADDFILES/$i"
2136 fi
2137 done
2139 sed '/^Rootfs list/!d;s/.*: //' description > /etc/tazlito/rootfs.list
2140 [ -s /etc/tazlito/rootfs.list ] || rm -f /etc/tazlito/rootfs.list
2142 action 'Updating %s...' 'tazlito.conf'
2143 [ -f tazlito.conf ] || cp /etc/tazlito/tazlito.conf .
2144 grep -v "^#VOLUM_NAME" < tazlito.conf | \
2145 sed "s/^VOLUM_NA/VOLUM_NAME=\"SliTaz $flavor\"\\n#VOLUM_NA/" \
2146 > tazlito.conf.$$ && mv tazlito.conf.$$ tazlito.conf
2147 sed -i "s/ISO_NAME=.*/ISO_NAME=\"slitaz-$flavor\"/" tazlito.conf
2148 status
2150 footer 'Flavor is ready to be generated by `tazlito gen-distro`'
2151 cleanup
2152 ;;
2155 iso2flavor)
2156 [ -z "$3" -o ! -s "$2" ] && die 'Usage: tazlito iso2flavor <image.iso> <flavor_name>' \
2157 '\n\nCreate a file <flavor_name>.flavor from the CD-ROM image file <image.iso>'
2159 FLAVOR=${3%.flavor}
2160 mkdir -p $TMP_DIR/iso $TMP_DIR/rootfs $TMP_DIR/flavor
2161 mount -o loop,ro $2 $TMP_DIR/iso
2162 flavordata $2 | (cd $TMP_DIR/flavor; cpio -i 2>/dev/null)
2163 if [ -s $TMP_DIR/iso/boot/rootfs1.gz -a \
2164 ! -s $TMP_DIR/flavor/*.desc ]; then
2165 _ 'META flavors are not supported.'
2166 umount -d $TMP_DIR/iso
2167 elif [ ! -s $TMP_DIR/iso/boot/rootfs.gz -a \
2168 ! -s $TMP_DIR/iso/boot/rootfs1.gz ]; then
2169 _ 'No %s in ISO image. Needs a SliTaz ISO.' '/boot/rootfs.gz'
2170 umount -d $TMP_DIR/iso
2171 else
2172 for i in $(ls -r $TMP_DIR/iso/boot/rootfs*z); do
2173 uncompress $i | \
2174 ( cd $TMP_DIR/rootfs ; cpio -idmu > /dev/null 2>&1 )
2175 done
2176 if [ ! -s $TMP_DIR/rootfs/etc/slitaz-release ]; then
2177 _ 'No file %s in %s of ISO image. Needs a non-loram SliTaz ISO.' \
2178 '/etc/slitaz-release' '/boot/rootfs.gz'
2179 umount -d $TMP_DIR/iso
2180 else
2181 ROOTFS_SIZE=$(du -hs $TMP_DIR/rootfs | awk '{ print $1 }')
2182 RAM_SIZE=$(du -s $TMP_DIR/rootfs | awk '{ print 32*int(($1+36000)/32768) "M" }')
2183 cp -a $TMP_DIR/iso $TMP_DIR/rootcd
2184 ISO_SIZE=$(df -h $TMP_DIR/iso | awk 'END { print $2 }')
2185 BUILD_DATE=$(date '+%Y%m%d at %T' -r "$TMP_DIR/iso/md5sum")
2186 umount -d $TMP_DIR/iso
2187 INITRAMFS_SIZE=$(du -chs $TMP_DIR/rootcd/boot/rootfs*.gz | awk 'END { print $1 }')
2188 rm -f $TMP_DIR/rootcd/boot/rootfs.gz $TMP_DIR/rootcd/md5sum
2189 mv $TMP_DIR/rootcd/boot $TMP_DIR/rootfs
2190 sed 's/.* \(.*\).tazpkg*/\1/' > $TMP_DIR/$FLAVOR.pkglist \
2191 < $TMP_DIR/rootfs$INSTALLED.md5
2192 PKGCNT=$(grep -v ^# $TMP_DIR/$FLAVOR.pkglist | wc -l | awk '{ print $1 }')
2193 if [ -s $TMP_DIR/flavor/*desc ]; then
2194 cp $TMP_DIR/flavor/*.desc $TMP_DIR/$FLAVOR.desc
2195 [ -s $TMP_DIR/$FLAVOR.receipt ] &&
2196 cp $TMP_DIR/flavor/*.receipt $TMP_DIR/$FLAVOR.receipt
2197 for i in rootfs rootcd ; do
2198 [ -s $TMP_DIR/flavor/*.list$i ] &&
2199 sed 's/.\{1,45\}//;/^\.$/d' $TMP_DIR/flavor/*.list$i | \
2200 ( cd $TMP_DIR/$i ; cpio -o -H newc ) | dogzip $TMP_DIR/$FLAVOR.$i
2201 done
2202 else
2203 find_flavor_rootfs $TMP_DIR/rootfs
2204 [ -d $TMP_DIR/rootfs/boot ] && mv $TMP_DIR/rootfs/boot $TMP_DIR/rootcd
2205 for i in rootfs rootcd ; do
2206 [ "$(ls $TMP_DIR/$i)" ] &&
2207 ( cd "$TMP_DIR/$i"; find * | cpio -o -H newc ) | dogzip "$TMP_DIR/$FLAVOR.$i"
2208 done
2209 unset VERSION MAINTAINER
2210 echo -en "Flavor short description \007: "; read -t 30 DESCRIPTION
2211 if [ -n "$DESCRIPTION" ]; then
2212 _n 'Flavor version : '; read -t 30 VERSION
2213 _n 'Flavor maintainer (your email) : '; read -t 30 MAINTAINER
2214 fi
2216 cat > $TMP_DIR/$FLAVOR.desc <<EOT
2217 Flavor : $FLAVOR
2218 Description : ${DESCRIPTION:-SliTaz $FLAVOR flavor}
2219 Version : ${VERSION:-1.0}
2220 Maintainer : ${MAINTAINER:-nobody@slitaz.org}
2221 LiveCD RAM size : $RAM_SIZE
2222 Build date : $BUILD_DATE
2223 Packages : $PKGCNT
2224 Rootfs size : $ROOTFS_SIZE
2225 Initramfs size : $INITRAMFS_SIZE
2226 ISO image size : $ISO_SIZE
2227 ================================================================================
2229 EOT
2230 longline "Tazlito can't detect each file installed during \
2231 a package post_install. You should extract this flavor (tazlito extract-flavor \
2232 $FLAVOR), check the files in /home/slitaz/flavors/$(cat /etc/slitaz-release)/$FLAVOR/rootfs \
2233 tree and remove files generated by post_installs.
2234 Check /home/slitaz/flavors/$(cat /etc/slitaz-release)/$FLAVOR/receipt too and \
2235 repack the flavor (tazlito pack-flavor $FLAVOR)"
2236 fi
2237 ( cd $TMP_DIR; ls $FLAVOR.* | cpio -o -H newc ) | dogzip $FLAVOR.flavor
2238 fi
2239 fi
2240 rm -rf $TMP_DIR
2241 ;;
2244 gen-distro)
2245 # Generate a live distro tree with a set of packages.
2247 check_root
2248 start_time=$(date +%s)
2250 # Tazlito options: --iso or --cdrom
2251 CDROM=''
2252 [ -n "$iso" ] && CDROM="-o loop $iso"
2253 [ -n "$cdrom" ] && CDROM="/dev/cdrom"
2255 # Check if a package list was specified on cmdline.
2256 if [ -f "$2" ]; then
2257 LIST_NAME="$2"
2258 else
2259 LIST_NAME='distro-packages.list'
2260 fi
2262 [ -d "$ROOTFS" -a -z "$forced" ] && die "A rootfs exists in '$DISTRO'." \
2263 'Please clean the distro tree or change directory path.'
2264 [ -d "$ROOTFS" ] && rm -rf "$ROOTFS"
2265 [ -d "$ROOTCD" ] && rm -rf "$ROOTCD"
2267 # If list not given: build list with all installed packages
2268 if [ ! -f "$LIST_NAME" -a -f "$LOCALSTATE/installed.info" ]; then
2269 awk -F$'\t' '{print $1}' "$LOCALSTATE/installed.info" >> "$LIST_NAME"
2270 fi
2272 # Exit if no list name.
2273 [ ! -f "$LIST_NAME" ] && die 'No packages list found or specified. Please read the docs.'
2275 # Start generation.
2276 title 'Tazlito generating a distro'
2278 # Misc checks
2279 mkdir -p "$PACKAGES_REPOSITORY"
2280 REPACK=$(yesorno 'Repack packages from rootfs?' 'n')
2281 newline
2283 # Mount CD-ROM to be able to repack boot-loader packages
2284 if [ ! -e /boot -a -n "$CDROM" ]; then
2285 mkdir $TMP_MNT
2286 if mount -r "$CDROM $TMP_MNT" 2>/dev/null; then
2287 ln -s "$TMP_MNT/boot" /
2288 if [ ! -d "$ADDFILES/rootcd" ] ; then
2289 mkdir -p "$ADDFILES/rootcd"
2290 for i in $(ls $TMP_MNT); do
2291 [ "$i" == 'boot' ] && continue
2292 cp -a "$TMP_MNT/$i" "$ADDFILES/rootcd"
2293 done
2294 fi
2295 else
2296 rmdir "$TMP_MNT"
2297 fi
2298 fi
2300 # Rootfs stuff.
2301 echo 'Preparing the rootfs directory...'
2302 mkdir -p "$ROOTFS"
2303 export root="$ROOTFS"
2304 # pass current 'mirror' to the root
2305 mkdir -p $root/var/lib/tazpkg $root/etc
2306 cp -f /var/lib/tazpkg/mirror $root/var/lib/tazpkg/mirror
2307 cp -f /etc/slitaz-release $root/etc/slitaz-release
2308 strip_versions "$LIST_NAME"
2310 if [ "$REPACK" == 'y' ]; then
2311 # Determine full packages list with all dependencies
2312 tmp_dir="$(mktemp -d)"
2313 cp "$LIST_NAME" "$tmp_dir/flavor.pkglist"
2314 touch "$tmp_dir/full.pkglist"
2315 module calc_sizes "$tmp_dir" 'flavor' "$tmp_dir/full.pkglist" >/dev/null
2317 awk -F$'\t' '{printf "%s %s\n", $1, $2}' "$LOCALSTATE/installed.info" | \
2318 while read pkgname pkgver; do
2319 # Is package in full list?
2320 grep -q "^$pkgname$" "$tmp_dir/full.pkglist" || continue
2321 # Is package already repacked?
2322 [ -e "$PACKAGES_REPOSITORY/$pkgname-$pkgver.tazpkg" ] && continue
2323 _ 'Repacking %s...' "$pkgname-$pkgver"
2324 tazpkg repack "$pkgname" --quiet
2325 [ -f "$pkgname-$pkgver.tazpkg" ] && mv "$pkgname-$pkgver.tazpkg" "$PACKAGES_REPOSITORY"
2326 status
2327 done
2329 rm -r "$tmp_dir"
2330 fi
2332 if [ -f non-free.list ]; then
2333 # FIXME: working in the ROOTFS chroot?
2334 newline
2335 echo 'Preparing non-free packages...'
2336 cp 'non-free.list' "$ROOTFS/etc/tazlito/non-free.list"
2337 for pkg in $(cat 'non-free.list'); do
2338 if [ ! -d "$INSTALLED/$pkg" ]; then
2339 if [ ! -d "$INSTALLED/get-$pkg" ]; then
2340 tazpkg get-install get-$pkg
2341 fi
2342 get-$pkg "$ROOTFS"
2343 fi
2344 tazpkg repack $pkg
2345 pkg=$(ls $pkg*.tazpkg)
2346 grep -q "^$pkg$" $LIST_NAME || echo $pkg >> $LIST_NAME
2347 mv $pkg $PACKAGES_REPOSITORY
2348 done
2349 fi
2350 cp $LIST_NAME $DISTRO/distro-packages.list
2351 newline
2353 install_list_to_rootfs "$DISTRO/distro-packages.list" "$ROOTFS"
2355 cd $DISTRO
2356 cp distro-packages.list $ROOTFS/etc/tazlito
2357 # Copy all files from $ADDFILES/rootfs to the rootfs.
2358 if [ -d "$ADDFILES/rootfs" ] ; then
2359 action 'Copying addfiles content to the rootfs...'
2360 cp -a $ADDFILES/rootfs/* $ROOTFS
2361 status
2362 fi
2364 action 'Root filesystem is generated...'; status
2366 # Root CD part.
2367 action 'Preparing the rootcd directory...'
2368 mkdir -p $ROOTCD
2369 status
2371 # Move the boot dir with the Linux kernel from rootfs.
2372 # The boot dir goes directly on the CD.
2373 if [ -d "$ROOTFS/boot" ] ; then
2374 action 'Moving the boot directory...'
2375 mv $ROOTFS/boot $ROOTCD
2376 cd $ROOTCD/boot
2377 rm -rf grub*
2378 make_bzImage_hardlink
2379 status
2380 fi
2381 cd $DISTRO
2382 # Copy all files from $ADDFILES/rootcd to the rootcd.
2383 if [ -d "$ADDFILES/rootcd" ] ; then
2384 action 'Copying addfiles content to the rootcd...'
2385 cp -a $ADDFILES/rootcd/* $ROOTCD
2386 status
2387 fi
2388 # Execute the distro script used to perform tasks in the rootfs
2389 # before compression. Give rootfs path in arg
2390 [ -z "$DISTRO_SCRIPT" ] && DISTRO_SCRIPT="$TOP_DIR/distro.sh"
2391 if [ -x "$DISTRO_SCRIPT" ]; then
2392 echo 'Executing distro script...'
2393 sh $DISTRO_SCRIPT $DISTRO
2394 fi
2396 # Execute the custom_rules() found in receipt.
2397 if [ -s "$TOP_DIR/receipt" ]; then
2398 if grep -q ^custom_rules "$TOP_DIR/receipt"; then
2399 echo -e "Executing: custom_rules()\n"
2400 . "$TOP_DIR/receipt"
2401 custom_rules || echo -e "\nERROR: custom_rules() failed\n"
2402 fi
2403 fi
2405 # Multi-rootfs
2406 if [ -s /etc/tazlito/rootfs.list ]; then
2408 FLAVOR_LIST="$(awk '{
2409 for (i = 2; i <= NF; i+=2)
2410 printf "%s ", $i;
2411 }' /etc/tazlito/rootfs.list)"
2413 [ -s "$ROOTCD/boot/isolinux/isolinux.msg" ] &&
2414 sed -i "s/ *//;s/)/), flavors $FLAVOR_LIST/" \
2415 "$ROOTCD/boot/isolinux/isolinux.msg" 2>/dev/null
2417 [ -f "$ROOTCD/boot/isolinux/ifmem.c32" -o \
2418 -f "$ROOTCD/boot/isolinux/c32box.c32" ] ||
2419 cp '/boot/isolinux/c32box.c32' "$ROOTCD/boot/isolinux" 2>/dev/null ||
2420 cp '/boot/isolinux/ifmem.c32' "$ROOTCD/boot/isolinux"
2422 n=0
2423 last=$ROOTFS
2424 while read flavor; do
2425 n=$(($n+1))
2426 mkdir ${ROOTFS}0$n
2427 export root="${ROOTFS}0$n"
2428 # initial tazpkg setup in empty rootfs
2429 tazpkg --root=$root >/dev/null 2>&1
2431 newline
2432 boldify "Building $flavor rootfs..."
2434 [ -s "$TOP_DIR/$flavor.flavor" ] &&
2435 cp "$TOP_DIR/$flavor.flavor" .
2437 if [ ! -s "$flavor.flavor" ]; then
2438 # We may have it in $FLAVORS_REPOSITORY
2439 if [ -d "$FLAVORS_REPOSITORY/$flavor" ]; then
2440 tazlito pack-flavor $flavor
2441 else
2442 download $flavor.flavor
2443 fi
2444 fi
2446 action 'Extracting %s and %s...' "$flavor.pkglist" "$flavor.rootfs"
2447 zcat $flavor.flavor | cpio -i --quiet $flavor.pkglist $flavor.rootfs
2448 cp $flavor.pkglist $DISTRO/list-packages0$n
2449 status
2451 strip_versions "$DISTRO/list-packages0$n"
2453 install_list_to_rootfs "$DISTRO/list-packages0$n" "${ROOTFS}0$n"
2455 rm -rf ${ROOTFS}0$n/boot
2457 cd $DISTRO
2458 if [ -s $flavor.rootfs ]; then
2459 _n 'Adding %s rootfs extra files...' "$flavor"
2460 zcat < $flavor.rootfs | ( cd ${ROOTFS}0$n ; cpio -idmu )
2461 fi
2463 action 'Moving %s to %s' "list-packages0$n" "rootfs0$n"
2464 mv "$DISTRO/list-packages0$n" "${ROOTFS}0$n/etc/tazlito/distro-packages.list"
2465 status
2467 rm -f $flavor.flavor install-list
2468 mergefs ${ROOTFS}0$n $last
2469 last=${ROOTFS}0$n
2470 done <<EOT
2471 $(awk '{ for (i = 4; i <= NF; i+=2) print $i; }' < /etc/tazlito/rootfs.list)
2472 EOT
2473 #'
2474 i=$(($n+1))
2475 while [ $n -gt 0 ]; do
2476 mv ${ROOTFS}0$n ${ROOTFS}$i
2477 _ 'Compressing %s (%s)...' "${ROOTFS}0$n" "$(du -hs ${ROOTFS}$i | awk '{ print $1 }')"
2478 gen_initramfs ${ROOTFS}$i
2479 n=$(($n-1))
2480 i=$(($i-1))
2481 export LZMA_HISTORY_BITS=26
2482 done
2483 mv $ROOTFS ${ROOTFS}$i
2484 gen_initramfs ${ROOTFS}$i
2485 update_bootconfig "$ROOTCD/boot/isolinux" "$(cat /etc/tazlito/rootfs.list)"
2486 else
2487 # Initramfs and ISO image stuff.
2488 gen_initramfs $ROOTFS
2489 fi
2490 gen_livecd_isolinux
2491 distro_stats
2492 cleanup
2493 ;;
2496 clean-distro)
2497 # Remove old distro tree.
2499 check_root
2500 title 'Cleaning: %s' "$DISTRO"
2501 if [ -d "$DISTRO" ] ; then
2502 if [ -d "$ROOTFS" ] ; then
2503 action 'Removing the rootfs...'
2504 rm -f $DISTRO/$INITRAMFS
2505 rm -rf $ROOTFS
2506 status
2507 fi
2508 if [ -d "$ROOTCD" ] ; then
2509 action 'Removing the rootcd...'
2510 rm -rf $ROOTCD
2511 status
2512 fi
2513 action 'Removing eventual ISO image...'
2514 rm -f $DISTRO/$ISO_NAME.iso
2515 rm -f $DISTRO/$ISO_NAME.md5
2516 status
2517 fi
2518 footer
2519 ;;
2522 check-distro)
2523 # Check for a few LiveCD needed files not installed by packages.
2525 # TODO: Remove this function.
2526 # First two files are maintained by tazpkg while it runs on rootfs,
2527 # while last one file should be maintained by tazlito itself.
2528 check_rootfs
2529 title 'Checking distro: %s' "$ROOTFS"
2530 # SliTaz release info.
2531 rel='/etc/slitaz-release'
2532 if [ ! -f "$ROOTFS$rel" ]; then
2533 _ 'Missing release info: %s' "$rel"
2534 else
2535 action 'Release : %s' "$(cat $ROOTFS$rel)"
2536 status
2537 fi
2538 # Tazpkg mirror.
2539 if [ ! -f "$ROOTFS$LOCALSTATE/mirror" ]; then
2540 action 'Mirror URL : Missing %s' "$LOCALSTATE/mirror"
2541 todomsg
2542 else
2543 action 'Mirror configuration exists...'
2544 status
2545 fi
2546 # Isolinux msg
2547 if grep -q "cooking-XXXXXXXX" /$ROOTCD/boot/isolinux/isolinux.*g; then
2548 action 'Isolinux msg : Missing cooking date XXXXXXXX (ex %s)' "$(date +%Y%m%d)"
2549 todomsg
2550 else
2551 action 'Isolinux message seems good...'
2552 status
2553 fi
2554 footer
2555 ;;
2558 writeiso)
2559 # Writefs to ISO image including /home unlike gen-distro we don't use
2560 # packages to generate a rootfs, we build a compressed rootfs with all
2561 # the current filesystem similar to 'tazusb writefs'.
2563 DISTRO='/home/slitaz/distro'
2564 ROOTCD="$DISTRO/rootcd"
2565 COMPRESSION="${2:-none}"
2566 ISO_NAME="${3:-slitaz}"
2567 check_root
2568 # Start info
2569 title 'Write filesystem to ISO'
2570 longline "The command writeiso will write the current filesystem into a \
2571 suitable cpio archive (rootfs.gz) and generate a bootable ISO image (slitaz.iso)."
2572 newline
2573 emsg "<b>Archive compression:</b> <c 36>$COMPRESSION</c>"
2575 [ "$COMPRESSION" == 'gzip' ] && colorize 31 "gzip-compressed rootfs unsupported and may fail to boot"
2576 # Save some space
2577 rm -rf /var/cache/tazpkg/*
2578 rm -f /var/lib/tazpkg/*.bak
2579 rm -rf $DISTRO
2581 # Optionally remove sound card selection and screen resolution.
2582 if [ -z $LaunchedByTazpanel ]; then
2583 anser=$(yesorno 'Do you wish to remove the sound card and screen configs?' 'n')
2584 case $anser in
2585 y)
2586 action 'Removing current sound card and screen configurations...'
2587 rm -f /var/lib/sound-card-driver
2588 rm -f /var/lib/alsa/asound.state
2589 rm -f /etc/X11/xorg.conf ;;
2590 *)
2591 action 'Keeping current sound card and screen configurations...' ;;
2592 esac
2593 status
2594 newline
2596 # Optionally remove i18n settings
2597 anser=$(yesorno 'Do you wish to remove locale/keymap settings?' 'n')
2598 case $anser in
2599 y)
2600 action 'Removing current locale/keymap settings...'
2601 newline > /etc/locale.conf
2602 newline > /etc/keymap.conf ;;
2603 *)
2604 action 'Keeping current locale/keymap settings...' ;;
2605 esac
2606 status
2607 fi
2609 # Clean-up files by default
2610 newline > /etc/udev/rules.d/70-persistent-net.rules
2611 newline > /etc/udev/rules.d/70-persistant-cd.rules
2613 # Create list of files including default user files since it is defined in /etc/passwd
2614 # and some new users might have been added.
2615 cd /
2616 echo 'init' > /tmp/list
2617 for dir in bin etc sbin var dev lib root usr home opt; do
2618 [ -d $dir ] && find $dir
2619 done >> /tmp/list
2621 for dir in proc sys tmp mnt media media/cdrom media/flash media/usbdisk run run/udev; do
2622 [ -d $dir ] && echo $dir
2623 done >> /tmp/list
2625 sed '/var\/run\/.*pid$/d ; /var\/run\/utmp/d ; /.*\/.gvfs/d ; /home\/.*\/.cache\/.*/d' -i /tmp/list
2627 #if [ ! $(find /var/log/slitaz/tazpkg.log -size +4k) = "" ]; then
2628 # sed -i "/var\/log\/slitaz\/tazpkg.log/d" /tmp/list
2629 #fi
2630 mv -f /var/log/wtmp /tmp/tazlito-wtmp
2631 touch /var/log/wtmp
2633 for removelog in auth boot messages dmesg daemon slim .*old Xorg tazpanel cups; do
2634 sed -i "/var\/log\/$removelog/d" /tmp/list
2635 done
2637 # Generate initramfs with specified compression and display rootfs
2638 # size in realtime.
2639 rm -f /tmp/.write-iso* /tmp/rootfs 2>/dev/null
2641 write_initramfs &
2642 sleep 2
2643 cd - > /dev/null
2644 echo -en "\nFilesystem size:"
2645 while [ ! -f /tmp/rootfs ]; do
2646 sleep 1
2647 echo -en "\\033[18G$(du -sh /$INITRAMFS | awk '{print $1}') "
2648 done
2649 mv -f /tmp/tazlito-wtmp /var/log/wtmp
2650 echo -e "\n"
2651 rm -f /tmp/rootfs
2653 # Move freshly generated rootfs to the cdrom.
2654 mkdir -p $ROOTCD/boot
2655 mv -f /$INITRAMFS $ROOTCD/boot
2656 _ 'Located in: %s' "$ROOTCD/boot/$INITRAMFS"
2658 # Now we need the kernel and isolinux files.
2659 copy_from_cd() {
2660 cp /media/cdrom/boot/bzImage* $ROOTCD/boot
2661 cp -a /media/cdrom/boot/isolinux $ROOTCD/boot
2662 unmeta_boot $ROOTCD
2663 umount /media/cdrom
2666 if mount /dev/cdrom /media/cdrom 2>/dev/null; then
2667 copy_from_cd;
2668 elif mount | grep /media/cdrom; then
2669 copy_from_cd;
2670 #elif [ -f "$bootloader" -a -f /boot/vmlinuz*slitaz* ]; then
2671 # [ -f /boot/*slitaz ] && cp /boot/vmlinuz*slitaz $ROOTCD/boot/bzImage
2672 # [ -f /boot/*slitaz64 ] && cp /boot/vmlinuz*slitaz64 $ROOTCD/boot/bzImage64
2673 else
2674 touch /tmp/.write-iso-error
2675 longline "When SliTaz is running in RAM the kernel and bootloader \
2676 files are kept on the CD-ROM. `boldify ' Please insert a Live CD or run:
2677 # mount -o loop slitaz.iso /media/cdrom ' ` to let Tazlito copy the files."
2678 echo -en "----\nENTER to continue..."; read i
2679 [ ! -d /media/cdrom/boot/isolinux ] && exit 1
2680 copy_from_cd
2681 fi
2683 # Generate the iso image.
2684 touch /tmp/.write-iso
2685 newline
2686 cd $DISTRO
2687 create_iso $ISO_NAME.iso $ROOTCD
2688 action 'Creating the ISO md5sum...'
2689 md5sum $ISO_NAME.iso > $ISO_NAME.md5
2690 status
2692 footer "ISO image: $(du -sh $DISTRO/$ISO_NAME.iso)"
2693 rm -f /tmp/.write-iso
2695 if [ -z $LaunchedByTazpanel ]; then
2696 anser=$(yesorno 'Burn ISO to CD-ROM?' 'n')
2697 case $anser in
2698 y)
2699 umount /dev/cdrom 2>/dev/null
2700 eject
2701 echo -n "Please insert a blank CD-ROM and press ENTER..."
2702 read i && sleep 2
2703 tazlito burn-iso $DISTRO/$ISO_NAME.iso
2704 echo -en "----\nENTER to continue..."; read i ;;
2705 *)
2706 exit 0 ;;
2707 esac
2708 fi
2709 ;;
2712 burn-iso)
2713 # Guess CD-ROM device, ask user and burn the ISO.
2715 check_root
2716 DRIVE_NAME=$(grep "drive name" /proc/sys/dev/cdrom/info | cut -f3)
2717 DRIVE_SPEED=$(grep "drive speed" /proc/sys/dev/cdrom/info | cut -f3)
2718 # We can specify an alternative ISO from the cmdline.
2719 iso="${2:-$DISTRO/$ISO_NAME.iso}"
2720 [ ! -f "$iso" ] && die "Unable to find ISO: $iso"
2722 title 'Tazlito burn ISO'
2723 echo "CD-ROM device : /dev/$DRIVE_NAME"
2724 echo "Drive speed : $DRIVE_SPEED"
2725 echo "ISO image : $iso"
2726 footer
2728 case $(yesorno 'Burn ISO image?' 'n') in
2729 y)
2730 title 'Starting Wodim to burn the ISO...'
2731 sleep 2
2732 wodim speed=$DRIVE_SPEED dev=/dev/$DRIVE_NAME $iso
2733 footer 'ISO image is burned to CD-ROM.'
2734 ;;
2735 *)
2736 die 'Exiting. No ISO burned.'
2737 ;;
2738 esac
2739 ;;
2742 merge)
2743 # Merge multiple rootfs into one iso.
2745 if [ -z "$2" ]; then
2746 cat <<EOT
2747 Usage: tazlito merge size1 iso size2 rootfs2 [sizeN rootfsN]...
2749 Merge multiple rootfs into one ISO. Rootfs are like russian dolls
2750 i.e: rootfsN is a subset of rootfsN-1
2751 rootfs1 is found in ISO, sizeN is the RAM size needed to launch rootfsN.
2752 The boot loader will select the rootfs according to the RAM size detected.
2754 Example:
2755 $ tazlito merge 160M slitaz-core.iso 96M rootfs-justx.gz 32M rootfs-base.gz
2757 Will start slitaz-core with 160M+ RAM, slitaz-justX with 96M-160M RAM,
2758 slitaz-base with 32M-96M RAM and display an error message if RAM < 32M.
2760 EOT
2761 exit 2
2762 fi
2764 shift # skip merge
2765 append="$1 slitaz1"
2766 shift # skip size1
2767 mkdir -p $TMP_DIR/mnt $TMP_DIR/rootfs1
2769 ISO=$1.merged
2771 # Extract filesystems
2772 action 'Mounting %s' "$1"
2773 mount -o loop,ro $1 $TMP_DIR/mnt 2> /dev/null
2774 status || cleanup_merge
2776 cp -a $TMP_DIR/mnt $TMP_DIR/iso
2777 make_bzImage_hardlink $TMP_DIR/iso/boot
2778 umount -d $TMP_DIR/mnt
2779 if [ -f $TMP_DIR/iso/boot/rootfs1.gz ]; then
2780 _ '%s is already a merged iso. Aborting.' "$1"
2781 cleanup_merge
2782 fi
2783 if [ ! -f $TMP_DIR/iso/boot/isolinux/ifmem.c32 -a
2784 ! -f $TMP_DIR/iso/boot/isolinux/c32box.c32 ]; then
2785 if [ ! -f /boot/isolinux/ifmem.c32 -a
2786 ! -f /boot/isolinux/c32box.c32 ]; then
2787 cat <<EOT
2788 No file /boot/isolinux/ifmem.c32
2789 Please install syslinux package !
2790 EOT
2791 rm -rf $TMP_DIR
2792 exit 1
2793 fi
2794 cp /boot/isolinux/c32box.c32 $TMP_DIR/iso/boot/isolinux 2> /dev/null ||
2795 cp /boot/isolinux/ifmem.c32 $TMP_DIR/iso/boot/isolinux
2796 fi
2798 action 'Extracting %s' 'iso/rootfs.gz'
2799 extract_rootfs $TMP_DIR/iso/boot/rootfs.gz $TMP_DIR/rootfs1 &&
2800 [ -d $TMP_DIR/rootfs1/etc ]
2801 status || cleanup_merge
2803 n=1
2804 while [ -n "$2" ]; do
2805 shift # skip rootfs N-1
2806 p=$n
2807 n=$(($n + 1))
2808 append="$append $1 slitaz$n"
2809 shift # skip size N
2810 mkdir -p $TMP_DIR/rootfs$n
2812 action 'Extracting %s' "$1"
2813 extract_rootfs $1 $TMP_DIR/rootfs$n &&
2814 [ -d "$TMP_DIR/rootfs$n/etc" ]
2815 status || cleanup_merge
2817 mergefs $TMP_DIR/rootfs$n $TMP_DIR/rootfs$p
2818 action 'Creating %s' "rootfs$p.gz"
2819 pack_rootfs "$TMP_DIR/rootfs$p" "$TMP_DIR/iso/boot/rootfs$p.gz"
2820 status
2821 done
2822 action 'Creating %s' "rootfs$n.gz"
2823 pack_rootfs "$TMP_DIR/rootfs$n" "$TMP_DIR/iso/boot/rootfs$n.gz"
2824 status
2825 rm -f $TMP_DIR/iso/boot/rootfs.gz
2826 update_bootconfig $TMP_DIR/iso/boot/isolinux "$append"
2827 create_iso $ISO $TMP_DIR/iso
2828 rm -rf $TMP_DIR
2829 ;;
2832 repack)
2833 # Repack an iso with maximum lzma compression ratio.
2835 ISO=$2
2836 mkdir -p $TMP_DIR/mnt
2838 # Extract filesystems
2839 action 'Mounting %s' "$ISO"
2840 mount -o loop,ro $ISO $TMP_DIR/mnt 2>/dev/null
2841 status || cleanup_merge
2843 cp -a $TMP_DIR/mnt $TMP_DIR/iso
2844 umount -d $TMP_DIR/mnt
2846 for i in $TMP_DIR/iso/boot/rootfs* ; do
2847 action 'Repacking %s' "$(basename $i)"
2848 uncompress $i 2>/dev/null > $TMP_DIR/rootfs
2849 lzma e $TMP_DIR/rootfs $i $(lzma_switches $TMP_DIR/rootfs)
2850 align_to_32bits $i
2851 status
2852 done
2854 create_iso $ISO $TMP_DIR/iso
2855 rm -rf $TMP_DIR
2856 ;;
2859 build-loram)
2860 # Build a Live CD for low RAM systems.
2862 ISO="$2"
2863 OUTPUT="$3"
2864 [ -z "$3" ] && \
2865 die "Usage: tazlito build-loram <input>.iso <output>.iso [cdrom|smallcdrom|http|ram]"
2866 mkdir -p "$TMP_DIR/iso"
2867 mount -o loop,ro -t iso9660 "$ISO" "$TMP_DIR/iso"
2868 loopdev=$( (losetup -a 2>/dev/null || losetup) | sed "/$(echo $ISO | sed 's|/|\\/|g')$/!d;s/:.*//;q")
2869 if ! check_iso_for_loram ; then
2870 umount -d "$TMP_DIR/iso"
2871 die "$ISO is not a valid SliTaz live CD. Abort."
2872 fi
2873 case "$4" in
2874 cdrom) build_loram_cdrom ;;
2875 http) build_loram_http ;;
2876 *) build_loram_ram "$5" ;;
2877 esac
2878 umount $TMP_DIR/iso # no -d: needs /proc
2879 losetup -d $loopdev
2880 rm -rf $TMP_DIR
2881 ;;
2884 emu-iso)
2885 # Emulate an ISO image with Qemu.
2886 iso="${2:-$DISTRO/$ISO_NAME.iso}"
2887 [ -f "$iso" ] || die "Unable to find ISO file '$iso'."
2888 [ -x '/usr/bin/qemu' ] || die "Unable to find Qemu binary. Please install package 'qemu'."
2889 echo -e "\nStarting Qemu emulator:\n"
2890 echo -e "qemu $QEMU_OPTS $iso\n"
2891 qemu $QEMU_OPTS $iso
2892 ;;
2895 deduplicate)
2896 # Deduplicate files in a tree
2897 shift
2898 deduplicate "$@"
2899 ;;
2902 usage|*)
2903 # Print usage also for all unknown commands.
2904 usage
2905 ;;
2906 esac
2908 exit 0