tazlito view tazlito @ rev 412

Rewrite some parts of tazlito, add man pages. Working in progress...
author Aleksej Bobylev <al.bobylev@gmail.com>
date Sat Feb 20 17:06:44 2016 +0200 (2016-02-20)
parents b75c89be345f
children bd4b1f42430b
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-2016 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://mirror.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 }
63 # Try to include config file, continue if command is gen-config or exit.
64 # The main config used by default is in /etc/tazlito.
65 # Specific distro config file can be put in a distro tree.
66 for i in /etc/tazlito "$TOP_DIR"; do
67 [ -f "$i/tazlito.conf" ] && CONFIG_FILE="$i/tazlito.conf"
68 done
70 [ -z "$CONFIG_FILE" -a "$COMMAND" != 'gen-config' ] && \
71 die 'Unable to find any configuration file.' \
72 'Please read the docs or run `tazlito gen-config` to get an empty config file.'
74 . $CONFIG_FILE
76 # While Tazpkg is not used the default mirror URL file does not exist
77 # and user can't recharge the list of flavors.
78 [ $(id -u) -eq 0 -a ! -f "$MIRROR" ] && echo "$DEFAULT_MIRROR" > $MIRROR
80 # Set the rootfs and rootcd path with $DISTRO
81 # configuration variable.
82 ROOTFS="$DISTRO/rootfs"
83 ROOTCD="$DISTRO/rootcd"
88 #####################
89 # Tazlito functions #
90 #####################
93 # Print the usage.
95 usage () {
96 [ $(basename $0) == 'tazlito' ] && cat <<EOT
98 SliTaz Live Tool - Version: $(colorize 34 "$VERSION")
100 $(boldify "Usage:") tazlito [command] [list|iso|flavor|compression] [dir|iso]
102 $(boldify "Commands:")
103 EOT
104 optlist "\
105 usage Print this short usage.
106 stats View Tazlito and distro configuration statistics.
107 list-addfiles Simple list of additional files in the rootfs.
108 gen-config Generate a new configuration file for a distro.
109 configure Configure the main config file or a specific tazlito.conf.
110 gen-iso Generate a new ISO from a distro tree.
111 gen-initiso Generate a new initramfs and ISO from the distro tree.
112 list-flavors List all flavors available on the mirror.
113 gen-flavor Generate a new Live CD description.
114 gen-liveflavor Generate a Live CD description from current system.
115 show-flavor Show Live CD description.
116 get-flavor Get a flavor's list of packages (--noup to skip update).
117 upgrade-flavor Update package list to the latest available versions.
118 extract-flavor Extract a *.flavor file into $FLAVORS_REPOSITORY.
119 pack-flavor Pack (and update) a flavor from $FLAVORS_REPOSITORY.
120 iso2flavor Create a flavor file from a SliTaz ISO image.
121 extract-distro Extract an ISO to a directory and rebuild Live CD tree.
122 gen-distro Generate a Live distro and ISO from a list of packages.
123 clean-distro Remove all files generated by gen-distro.
124 check-distro Help to check if distro is ready to release.
125 writeiso Use running system to generate a bootable ISO (with /home).
126 merge Merge multiple rootfs into one ISO.
127 deduplicate Deduplicate files in a tree.
128 repack Recompress rootfs into ISO with maximum ratio.
129 build-loram Generate a Live CD for low-RAM systems.
130 emu-iso Emulate an ISO image with QEMU.
131 burn-iso Burn ISO image to a CD-ROM using Wodim.
132 "
133 }
136 yesorno() {
137 local answer
138 echo -n "$1 (y=yes, n=no) [$2] " >&2
139 case "$DEFAULT_ANSWER" in
140 Y|y) answer="y";;
141 N|n) answer="n";;
142 *)
143 read answer
144 [ -z "$answer" ] && answer="$2"
145 [ "$answer" != 'y' -a "$answer" != 'n' ] && answer="$2"
146 ;;
147 esac
148 echo "$answer"
149 }
152 field() {
153 grep "^$1" "$2" | \
154 case "$1" in
155 Desc*) sed 's|^.*: *||';;
156 *) sed 's/.*: \([0-9KMG\.]*\).*/\1/';;
157 esac
158 }
161 todomsg() {
162 echo -e "\\033[70G[ \\033[1;31mTODO\\033[0;39m ]"
163 }
166 # Download a file from this mirror
168 download_from() {
169 local i mirrors="$1"
170 shift
171 for i in $mirrors; do
172 case "$i" in
173 http://*|ftp://*|https://*)
174 wget -c $i$@ && break;;
175 *)
176 cp $i/$1 . && break;;
177 esac
178 done
179 }
182 # Download a file trying all mirrors
184 download() {
185 local i
186 for i in $(cat $MIRROR $LOCALSTATE/undigest/*/mirror 2>/dev/null); do
187 download_from "$i" "$@" && break
188 done
189 }
192 # Execute hooks provided by some packages
194 genisohooks() {
195 local here="$(pwd)"
196 for i in $(ls $ROOTFS/etc/tazlito/*.$1 2>/dev/null); do
197 cd $ROOTFS
198 . $i $ROOTCD
199 done
200 cd "$here"
201 }
204 # Echo the package name if the tazpkg is already installed
206 installed_package_name() {
207 local tazpkg="$1" package VERSION EXTRAVERSION
209 # Try to find package name and version to be able
210 # to repack it from installation
211 # A dash (-) can exist in name *and* in version
212 package=${tazpkg%-*}
213 i=$package
214 while true; do
215 unset VERSION EXTRAVERSION
216 eval $(grep -s ^VERSION= $INSTALLED/$i/receipt)
217 eval $(grep -s ^EXTRAVERSION= $INSTALLED/$i/receipt)
218 if [ "$i-$VERSION$EXTRAVERSION" == "$tazpkg" ]; then
219 echo $i
220 break
221 fi
222 case "$i" in
223 *-*);;
224 *) break;;
225 esac
226 i=${i%-*}
227 done
228 }
231 # Check for the rootfs tree.
233 check_rootfs() {
234 [ -d "$ROOTFS/etc" ] || die 'Unable to find a distro rootfs...'
235 }
238 # Check for the boot dir into the root CD tree.
240 verify_rootcd() {
241 [ -d "$ROOTCD/boot" ] || die 'Unable to find the rootcd boot directory...'
242 }
245 # isolinux.conf doesn't know the kernel version.
246 # We name the kernel image 'bzImage'.
247 # isolinux/syslinux first tries the '64' suffix with a 64bits cpu.
249 make_bzImage_hardlink() {
250 if [ -s ${1:-.}/vmlinuz*slitaz ]; then
251 rm -f ${1:-.}/bzImage 2>/dev/null
252 ln ${1:-.}/vmlinuz*slitaz ${1:-.}/bzImage
253 fi
254 if [ -s ${1:-.}/vmlinuz*slitaz64 ]; then
255 rm -f ${1:-.}/bzImage64 2> /dev/null
256 ln ${1:-.}/vmlinuz*slitaz64 ${1:-.}/bzImage64
257 fi
258 }
261 create_iso() {
262 cd $2
263 deduplicate
265 action 'Computing md5...'
266 find * -type f ! -name md5sum ! -name 'vmlinuz*' -exec md5sum {} \; > md5sum
267 sed -i -e '/ boot\/isolinux\/isolinux.bin$/d' \
268 -e '/ boot\/isolinux\/boot.cat$/d' md5sum
269 status
271 cd - >/dev/null
272 title 'Generating ISO image'
274 echo "Generating $1"
275 make_bzImage_hardlink $2/boot
276 genisoimage -R -o $1 -b boot/isolinux/isolinux.bin \
277 -c boot/isolinux/boot.cat -no-emul-boot -boot-load-size 4 \
278 -V "$VOLUM_NAME" -p "$PREPARED" -input-charset utf-8 \
279 -copyright README -P "www.slitaz.org" -boot-info-table $2
281 if [ -x '/usr/bin/isohybrid' ]; then
282 action 'Creating hybrid ISO...'
283 /usr/bin/isohybrid $1 -entry 2 2>/dev/null
284 status
285 fi
287 if [ -s '/etc/tazlito/info' ]; then
288 if [ $(stat -c %s /etc/tazlito/info) -lt $(( 31*1024 )) ]; then
289 action 'Storing ISO info...'
290 dd if=/etc/tazlito/info bs=1k seek=1 of=$1 conv=notrunc 2>/dev/null
291 status
292 fi
293 fi
295 if [ -x '/usr/bin/iso2exe' ]; then
296 echo 'Creating EXE header...'
297 /usr/bin/iso2exe $1 2>/dev/null
298 fi
299 }
302 # Generate a new ISO image using isolinux.
304 gen_livecd_isolinux() {
305 # Some packages may want to alter iso
306 genisohooks iso
307 [ ! -f "$ROOTCD/boot/isolinux/isolinux.bin" ] && die 'Unable to find isolinux binary.'
309 # Set date for boot msg.
310 if grep -q 'XXXXXXXX' "$ROOTCD/boot/isolinux/isolinux.cfg"; then
311 DATE=$(date +%Y%m%d)
312 action 'Setting build date to: %s...' "$DATE"
313 sed -i "s/XXXXXXXX/$DATE/" "$ROOTCD/boot/isolinux/isolinux.cfg"
314 status
315 fi
317 cd $DISTRO
318 create_iso $ISO_NAME.iso $ROOTCD
320 action 'Creating the ISO md5sum...'
321 md5sum $ISO_NAME.iso > $ISO_NAME.md5
322 status
324 separator
325 # Some packages may want to alter final iso
326 genisohooks final
327 }
330 lzma_history_bits() {
331 #
332 # This generates an ISO which boots with Qemu but gives
333 # rootfs errors in frugal or liveUSB mode.
334 #
335 # local n
336 # local sz
337 # n=20 # 1Mb
338 # sz=$(du -sk $1 | cut -f1)
339 # while [ $sz -gt 1024 -a $n -lt 28 ]; do
340 # n=$(( $n + 1 ))
341 # sz=$(( $sz / 2 ))
342 # done
343 # echo $n
344 echo 24
345 }
348 lzma_switches() {
349 local proc_num=$(grep -sc '^processor' /proc/cpuinfo)
350 echo "-d$(lzma_history_bits $1) -mt${proc_num:-1}"
351 }
354 lzma_set_size() {
355 # Update size field for lzma'd file packed using -si switch
356 return # Need to fix kernel code?
358 local n i
359 n=$(unlzma < $1 | wc -c)
360 for i in $(seq 1 8); do
361 printf '\\\\x%02X' $(($n & 255))
362 n=$(($n >> 8))
363 done | xargs echo -en | dd of=$1 conv=notrunc bs=1 seek=5 2>/dev/null
364 }
367 align_to_32bits() {
368 local size=$(stat -c %s ${1:-/dev/null})
369 [ $((${size:-0} & 3)) -ne 0 ] &&
370 dd if=/dev/zero bs=1 count=$((4 - ($size & 3))) >> $1 2>/dev/null
371 }
374 # Pack rootfs
376 pack_rootfs() {
377 ( cd $1; find . -print | cpio -o -H newc ) | \
378 case "$COMPRESSION" in
379 none)
380 _ 'Creating %s without compression...' 'initramfs'
381 cat > $2
382 ;;
383 gzip)
384 _ 'Creating %s with gzip compression...' 'initramfs'
385 gzip -9 > $2
386 ;;
387 *)
388 _ 'Creating %s with lzma compression...' 'initramfs'
389 lzma e -si -so $(lzma_switches $1) > $2
390 lzma_set_size $2
391 ;;
392 esac
393 align_to_32bits $2
394 echo 1 > /tmp/rootfs
395 }
398 # Compression functions for writeiso.
400 write_initramfs() {
401 case "$COMPRESSION" in
402 lzma)
403 _n 'Creating %s with lzma compression...' "$INITRAMFS"
404 cpio -o -H newc | lzma e -si -so $(lzma_switches) > "/$INITRAMFS"
405 align='y'
406 lzma_set_size "/$INITRAMFS"
407 ;;
408 gzip)
409 _ 'Creating %s with gzip compression...' "$INITRAMFS"
410 cpio -o -H newc | gzip -9 > "/$INITRAMFS"
411 [ -x /usr/bin/advdef ] && advdef -z4 "/$INITRAMFS"
412 ;;
413 *)
414 # align='y'
415 _ 'Creating %s without compression...' "$INITRAMFS"
416 cpio -o -H newc > "/$INITRAMFS"
417 ;;
418 esac < /tmp/list
419 [ "$align" == 'y' -a -z "$noalign" ] && align_to_32bits "/$INITRAMFS"
420 echo 1 > /tmp/rootfs
421 }
424 # Deduplicate files (MUST be on the same filesystem).
426 deduplicate() {
427 find "${@:-.}" -type f -size +0c -xdev -exec stat -c '%s-%a-%u-%g %i %h %n' {} \; | sort | \
428 (
429 save=0; hardlinks=0; old_attr=""; old_inode=""; old_link=""; old_file=""
430 while read attr inode link file; do
431 [ -L "$file" ] && continue
432 if [ "$attr" == "$old_attr" -a "$inode" != "$old_inode" ]; then
433 if cmp "$file" "$old_file" >/dev/null 2>&1 ; then
434 rm -f "$file"
435 if ln "$old_file" "$file" 2>/dev/null; then
436 inode="$old_inode"
437 [ "$link" -eq 1 ] && hardlinks=$(($hardlinks+1)) &&
438 save="$(($save+(${attr%%-*}+512)/1024))"
439 else
440 cp -a "$old_file" "$file"
441 fi
442 fi
443 fi
444 old_attr="$attr" ; old_inode="$inode" ; old_file="$file"
445 done
446 echo "$save Kbytes saved in $hardlinks duplicate files."
447 )
449 find "$@" -type l -xdev -exec stat -c '%s-%u-%g-TARGET- %i %h %n' {} \; | sort | \
450 (
451 old_attr=""; hardlinks=0;
452 while read attr inode link file; do
453 attr="${attr/-TARGET-/-$(readlink $file)}"
454 if [ "$attr" == "$old_attr" ]; then
455 if [ "$inode" != "$old_inode" ]; then
456 rm -f "$file"
457 if ln "$old_file" "$file" 2>/dev/null; then
458 [ "$link" -eq 1 ] && hardlinks=$(($hardlinks+1))
459 else
460 cp -a "$old_file" "$file"
461 fi
462 fi
463 else
464 old_file="$file"
465 old_attr="$attr"
466 old_inode="$inode"
467 fi
468 done
469 echo "$hardlinks duplicate symlinks."
470 )
471 }
474 # Generate a new initramfs from the root filesystem.
476 gen_initramfs() {
477 # Just in case CTRL+c
478 rm -f $DISTRO/gen
480 # Some packages may want to alter rootfs
481 genisohooks rootfs
482 cd $1
484 # Link duplicate files
485 deduplicate
487 # Use lzma if installed. Display rootfs size in realtime.
488 rm -f /tmp/rootfs 2>/dev/null
489 pack_rootfs . $DISTRO/$(basename $1).gz &
490 sleep 2
491 echo -en "\nFilesystem size:"
492 while [ ! -f /tmp/rootfs ]; do
493 sleep 1
494 echo -en "\\033[18G$(du -sh $DISTRO/$(basename $1).gz | awk '{print $1}') "
495 done
496 echo -e "\n"
497 rm -f /tmp/rootfs
498 cd $DISTRO
499 mv $(basename $1).gz $ROOTCD/boot
500 }
503 distro_sizes() {
504 if [ -n "$start_time" ]; then
505 time=$(($(date +%s) - $start_time))
506 sec=$time
507 div=$(( ($time + 30) / 60))
508 [ "$div" -ne 0 ] && min="~ ${div}m"
509 echo "Build time : ${sec}s $min"
510 fi
511 cat <<EOT
512 Build date : $(date +%Y%m%d)
513 Packages : $(ls -1 $ROOTFS*$INSTALLED/*/receipt | wc -l)
514 Rootfs size : $(du -csh $ROOTFS*/ | awk 'END { print $1 }')
515 Initramfs size : $(du -csh $ROOTCD/boot/rootfs*.gz | awk 'END { print $1 }')
516 ISO image size : $(du -sh $ISO_NAME.iso | awk '{ print $1 }')
517 EOT
518 footer "Image is ready: $ISO_NAME.iso"
519 }
522 # Print ISO and rootfs size.
524 distro_stats() {
525 title 'Distro statistics: %s' "$DISTRO"
526 distro_sizes
527 }
530 # Create an empty configuration file.
532 empty_config_file() {
533 cat >> tazlito.conf <<"EOF"
534 # tazlito.conf: Tazlito (SliTaz Live Tool) configuration file.
535 #
537 # Name of the ISO image to generate.
538 ISO_NAME=""
540 # ISO image volume name.
541 VOLUM_NAME="SliTaz"
543 # Name of the preparer.
544 PREPARED="$USER"
546 # Path to the packages repository and the packages.list.
547 PACKAGES_REPOSITORY=""
549 # Path to the distro tree to gen-distro from a list of packages.
550 DISTRO=""
552 # Path to the directory containing additional files
553 # to copy into the rootfs and rootcd of the LiveCD.
554 ADDFILES="$DISTRO/addfiles"
556 # Default answer for binary question (Y or N)
557 DEFAULT_ANSWER="ASK"
559 # Compression utility (lzma, gzip or none)
560 COMPRESSION="lzma"
561 EOF
562 }
565 # Extract rootfs.gz somewhere
567 extract_rootfs() {
568 # Detect compression format: *.lzma.cpio, *.gzip.cpio, or *.cpio
569 # First part (lzcat or zcat) may not fail, but cpio will fail on uncorrect format
570 (cd "$2"; lzcat "$1" | cpio -idm --quiet 2>/dev/null) && return
571 (cd "$2"; zcat "$1" | cpio -idm --quiet 2>/dev/null) && return
572 (cd "$2"; cat "$1" | cpio -idm --quiet 2>/dev/null)
573 }
576 # Extract flavor file to temp directory
578 extract_flavor() {
579 # Input: $1 - flavor name to extract;
580 # $2 = absent/empty: just extract 'outer layer'
581 # $2 = 'full': also extract 'inner' rootcd and rootfs archives, make files rename
582 # $2 = 'info': as 'full' and also make 'info' file to put into ISO
583 # Output: temp dir path where flavor was extracted
584 local f="$1.flavor" from to infos="$1.desc"
585 [ -f "$f" ] || die "File '$f' not found"
586 local dir="$(mktemp -d)"
587 zcat "$f" | (cd $dir; cpio -i --quiet >/dev/null)
589 if [ -n "$2" ]; then
590 cd $dir
592 [ -s "$1.receipt" ] && infos="$infos\n$1.receipt"
594 for i in rootcd rootfs; do
595 [ -f "$1.$i" ] || continue
596 mkdir "$i"
597 zcat "$1.$i" | (cd "$i"; cpio -idm --quiet 2>/dev/null)
598 zcat "$1.$i" | cpio -tv 2>/dev/null > "$1.list$i"; infos="$infos\n$1.list$i"
599 rm "$1.$i"
600 done
601 # Info to be stored inside ISO
602 [ "$2" == info ] && echo -e $infos | cpio -o -H newc | gzip -9 > info
603 rm $1.list*
605 # Renames
606 while read from to; do
607 [ -f "$from" ] || continue
608 mv "$from" "$to"
609 done <<EOT
610 $1.nonfree non-free.list
611 $1.pkglist packages.list
612 $1-distro.sh distro.sh
613 $1.receipt receipt
614 $1.mirrors mirrors
615 $1.desc description
616 EOT
617 fi
619 echo $dir
620 }
623 # Pack flavor file from temp directory
625 pack_flavor() {
626 (cd "$1"; ls | grep -v err | cpio -o -H newc) | gzip -9 > "$2.flavor"
627 }
630 # Remove duplicate files
632 mergefs() {
633 # Note, many packages have files with spaces in the name
634 IFS=$'\n'
636 local size1=$(du -hs "$1" | awk '{ print $1 }')
637 local size2=$(du -hs "$2" | awk '{ print $1 }')
638 action 'Merge %s (%s) into %s (%s)' "$(basename "$1")" "$size1" "$(basename "$2")" "$size2"
640 # merge symlinks files and devices
641 ( cd "$1"; find ) | \
642 while read file; do
643 if [ -L "$1/$file" ]; then
644 [ -L "$2/$file" -a "$(readlink "$1/$file")" == "$(readlink "$2/$file")" ] &&
645 rm -f "$2/$file"
647 elif [ -f "$1/$file" ]; then
648 [ -f "$2/$file" ] && cmp -s "$1/$file" "$2/$file" &&
649 rm -f "$2/$file"
651 [ -f "$2/$file" ] &&
652 [ "$(basename "$file")" == 'volatile.cpio.gz' ] &&
653 [ "$(dirname $(dirname "$file"))" == ".$INSTALLED" ] &&
654 rm -f "$2/$file"
656 elif [ -b "$1/$file" ]; then
657 [ -b "$2/$file" ] &&
658 [ "$(stat -c '%a:%u:%g:%t:%T' "$1/$file")" == \
659 "$(stat -c '%a:%u:%g:%t:%T' "$2/$file")" ] &&
660 rm -f "$2/$file"
662 elif [ -c "$1/$file" ]; then
663 [ -c "$2/$file" ] &&
664 [ "$(stat -c '%a:%u:%g:%t:%T' "$1/$file")" == \
665 "$(stat -c '%a:%u:%g:%t:%T' "$2/$file")" ] &&
666 rm -f "$2/$file"
667 fi
668 done
670 # cleanup directories; TODO: simplify
671 ( cd "$1"; find . -type d ) | sed '1!G;h;$!d' | \
672 while read file; do
673 [ -d "$2/$file" ] && rmdir "$2/$file" 2>/dev/null
674 done
676 unset IFS
677 status
678 }
681 cleanup_merge() {
682 rm -rf $TMP_DIR
683 exit 1
684 }
687 # Update isolinux config files for multiple rootfs
689 update_bootconfig() {
690 local files
691 echo -n "Updating boot config files..."
692 files="$(grep -l 'include common' $1/*.cfg)"
693 for file in $files; do
694 awk -v n=$(echo $2 | awk '{ print NF/2 }') '{
695 if (/label/) label=$0;
696 else if (/kernel/) kernel=$0;
697 else if (/append/) {
698 i=index($0,"rootfs.gz");
699 append=substr($0,i+9);
700 }
701 else if (/include/) {
702 for (i = 1; i <= n; i++) {
703 print label i
704 print kernel;
705 initrd="initrd=/boot/rootfs" n ".gz"
706 for (j = n - 1; j >= i; j--) {
707 initrd=initrd ",/boot/rootfs" j ".gz";
708 }
709 printf "\tappend %s%s\n",initrd,append;
710 print "";
711 }
712 print;
713 }
714 else print;
715 }' < $file > $file.$$
716 mv -f $file.$$ $file
717 done
718 sel="$(echo $2 | awk '{
719 for (i=1; i<=NF; i++)
720 if (i % 2 == 0) printf " slitaz%d", i/2
721 else printf " %s", $i
722 }')"
724 [ -s $1/common.cfg ] && cat >> $1/common.cfg <<EOT
726 label slitaz
727 kernel /boot/isolinux/ifmem.c32
728 append$sel noram
730 label noram
731 config noram.cfg
733 EOT
735 # Update vesamenu
736 if [ -s "$1/isolinux.cfg" ]; then
737 files="$files $1/isolinux.cfg"
738 awk -v n=$(echo $2 | awk '{ print NF/2 }') -v "sel=$sel" '
739 BEGIN {
740 kernel = " COM32 c32box.c32"
741 }
742 {
743 if (/ROWS/) print "MENU ROWS " n+$3;
744 else if (/TIMEOUTROW/) print "MENU TIMEOUTROW " n+$3;
745 else if (/TABMSGROW/) print "MENU TABMSGROW " n+$3;
746 else if (/CMDLINEROW/) print "MENU CMDLINEROW " n+$3;
747 else if (/VSHIFT/) {
748 x = $3-n;
749 if (x < 0) x = 0;
750 print "MENU VSHIFT " x;
751 }
752 else if (/rootfs.gz/) {
753 linux = "";
754 if (/bzImage/) linux = "linux /boot/bzImage ";
755 i = index($0, "rootfs.gz");
756 append = substr($0, i+9);
757 print " kernel /boot/isolinux/ifmem.c32"
758 printf "\tappend%s noram", sel;
759 print ""
760 print "label noram"
761 print " MENU HIDE"
762 print " config noram.cfg"
763 print ""
764 for (i = 1; i <= n; i++) {
765 print "LABEL slitaz" i
766 printf "\tMENU LABEL SliTaz slitaz%d Live", i;
767 print kernel;
768 initrd = "initrd=/boot/rootfs" n ".gz"
769 for (j = n - 1; j >= i; j--) {
770 initrd = initrd ",/boot/rootfs" j ".gz";
771 }
772 printf "\tappend %s%s%s\n", linux, initrd, append;
773 print "";
774 }
775 }
776 else if (/bzImage/) kernel = $0;
777 else print;
778 }' < $1/isolinux.cfg > $1/isolinux.cfg.$$
779 mv $1/isolinux.cfg.$$ $1/isolinux.cfg
780 fi
782 [ -s $1/c32box.c32 ] && sed -i -e '/kernel.*ifmem/d' \
783 -e 's/append \([0-9]\)/append ifmem \1/' $1/isolinux.cfg
784 cat > $1/noram.cfg <<EOT
785 implicit 0
786 prompt 1
787 timeout 80
788 $(grep '^F[0-9]' $1/isolinux.cfg)
790 $([ -s $1/isolinux.msg ] && echo display isolinux.msg)
791 say Not enough RAM to boot slitaz. Trying hacker mode...
792 default hacker
793 label hacker
794 KERNEL /boot/bzImage
795 append rw root=/dev/null vga=normal
797 label reboot
798 EOT
800 if [ -s $1/c32box.c32 ]; then
801 cat >> $1/noram.cfg <<EOT
802 COM32 c32box.c32
803 append reboot
805 label poweroff
806 COM32 c32box.c32
807 append poweroff
809 EOT
810 else
811 echo " com32 reboot.c32" >> $1/noram.cfg
812 fi
814 # Restore real label names
815 [ -s $1/common.cfg ] && files="$1/common.cfg $files"
816 echo $2 | awk '{ for (i=NF; i>1; i-=2) printf "%d/%s\n",i/2,$i }' | \
817 while read pat; do
818 sed -i "s/slitaz$pat/" $files
819 done
820 status
821 }
824 # Install a missing package
826 install_package() {
827 if [ -z "$2" ]; then
828 _n 'Install package %s? ' "$1"
829 else
830 _n 'Install package %s for Kernel %s? ' "$1" "$2"
831 fi
832 echo -n '[y = yes] '
833 read answer
834 case "$answer" in
835 y*|Y*|o*|O*)
836 # We don't want package on host cache.
837 action 'Getting and installing package: %s' "$1"
838 yes y | tazpkg get-install $1 --quiet 2>&1 >> $log || exit 1
839 status ;;
840 *)
841 return 1 ;;
842 esac
843 }
846 # Check iso for loram transformation
848 check_iso_for_loram() {
849 [ -s "$TMP_DIR/iso/boot/rootfs.gz" ] ||
850 [ -s "$TMP_DIR/iso/boot/rootfs1.gz" ]
851 }
854 # Build initial rootfs for loram ISO ram/cdrom/http
856 build_initfs() {
857 urliso="mirror.slitaz.org mirror.switch.ch/ftp/mirror/slitaz \
858 download.tuxfamily.org/slitaz slitaz.c3sl.ufpr.br"
859 version=$(ls $TMP_DIR/iso/boot/vmlinuz-* | sed 's/.*vmlinuz-//')
860 [ -z "$version" ] && die "Can't find the kernel version." \
861 'No file /boot/vmlinuz-<version> in ISO image. Abort.'
863 [ -s /usr/share/boot/busybox-static ] || install_package busybox-static
864 need_lib=false
865 for i in bin dev run mnt proc tmp sys lib/modules; do
866 mkdir -p $TMP_DIR/initfs/$i
867 done
868 ln -s bin $TMP_DIR/initfs/sbin
869 ln -s . $TMP_DIR/initfs/usr
870 for aufs in aufs overlayfs; do
871 [ ! -f /lib/modules/$version/kernel/fs/$aufs/$aufs.ko.?z ] &&
872 install_package $aufs $version && break
873 done || return 1
874 cp /init $TMP_DIR/initfs/
875 # bootfloppybox will need floppy.ko.?z, /dev/fd0, /dev/tty0
876 cp /lib/modules/$version/kernel/drivers/block/floppy.ko.?z \
877 $TMP_DIR/initfs/lib/modules 2>/dev/null
878 cp -a /dev/tty0 /dev/fd0 $TMP_DIR/initfs/dev 2>/dev/null
879 cp /lib/modules/$version/kernel/fs/$aufs/$aufs.ko.?z \
880 $TMP_DIR/initfs/lib/modules
881 if [ "$1" == 'cdrom' ]; then
882 sed -i '/mod squashfs/d' $TMP_DIR/initfs/init
883 else
884 [ ! -f /usr/sbin/mksquashfs ] && ! install_package squashfs && return 1
885 while [ ! -f /lib/modules/$version/kernel/fs/squashfs/squashfs.ko.?z ]; do
886 install_package linux-squashfs $version || return 1
887 done
888 cp /lib/modules/$version/kernel/fs/squashfs/squashfs.ko.?z \
889 $TMP_DIR/initfs/lib/modules
890 ls /sbin/unsquashfs /usr/lib/liblzma.so* $INSTALLED/squashfs/* | \
891 cpio -o -H newc > $TMP_DIR/initfs/extractfs.cpio
892 fi
893 for i in $(ls /dev/[hs]d[a-f]*); do
894 cp -a $i $TMP_DIR/initfs/dev
895 done
896 if [ "$1" == 'http' ]; then
897 mkdir $TMP_DIR/initfs/etc
898 ln -s /proc/mounts $TMP_DIR/initfs/etc/mtab
899 cp /usr/share/udhcpc/default.script $TMP_DIR/initfs/lib/udhcpc
900 sed -i 's|/sbin/||' $TMP_DIR/initfs/lib/udhcpc
901 cp -a /dev/fuse $TMP_DIR/initfs/dev
902 if ! $need_lib && [ -x /usr/share/boot/fusermount-static ]; then
903 cp /usr/share/boot/fusermount-static $TMP_DIR/initfs/bin/httpfs
904 else
905 cp /usr/bin/fusermount $TMP_DIR/initfs/bin
906 need_lib=true
907 fi
908 if ! $need_lib && [ -x /usr/share/boot/httpfs-static ]; then
909 cp /usr/share/boot/httpfs-static $TMP_DIR/initfs/bin/httpfs
910 else
911 [ ! -f /usr/bin/httpfs ] && ! install_package httpfs-fuse && return 1
912 cp /usr/bin/httpfs $TMP_DIR/initfs/bin
913 cp -a /lib/librt* $TMP_DIR/initfs/lib
914 cp -a /lib/libdl* $TMP_DIR/initfs/lib
915 cp -a /lib/libpthread* $TMP_DIR/initfs/lib
916 cp -a /usr/lib/libfuse* $TMP_DIR/initfs/lib
917 cp -a /lib/libresolv* $TMP_DIR/initfs/lib
918 cp -a /lib/libnss_dns* $TMP_DIR/initfs/lib
919 need_lib=true
920 fi
921 cd $TMP_DIR/initfs
922 echo 'Getting slitaz-release...'
923 for i in $TMP_DIR/iso/boot/rootfs*.gz; do
924 (zcat $i 2>/dev/null || unlzma < $i) | cpio -idmu etc/slitaz-release >/dev/null
925 done
926 cd - > /dev/null
927 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"
928 echo -n "List of URLs to insert: "
929 read -t 30 urliso2
930 urliso="$urliso2 $urliso"
931 fi
932 if ! $need_lib && [ -x /usr/share/boot/busybox-static ]; then
933 cp /usr/share/boot/busybox-static $TMP_DIR/initfs/bin/busybox
934 sed -i 's/LD_T.*ot/newline/;s/".*ld-.*) /"/' $TMP_DIR/initfs/init
935 else
936 cp /bin/busybox $TMP_DIR/initfs/bin
937 need_lib=true
938 fi
939 for i in $($TMP_DIR/initfs/bin/busybox | awk \
940 '{ if (s) printf "%s",$0 } /Currently/ { s=1 }' | sed 's/,//g'); do
941 ln $TMP_DIR/initfs/bin/busybox $TMP_DIR/initfs/bin/$i
942 done
943 for i in /dev/console /dev/loop* /dev/null /dev/tty /dev/zero \
944 /dev/kmem /dev/mem /dev/random /dev/urandom; do
945 cp -a $i $TMP_DIR/initfs/dev
946 done
947 $need_lib && for i in /lib/ld-* /lib/lib[cm].so* /lib/lib[cm]-* ; do
948 cp -a $i $TMP_DIR/initfs/lib
949 done
950 [ "$1" == 'http' ] && cat > $TMP_DIR/initfs/init <<EOTEOT
951 #!/bin/sh
953 getarg() {
954 grep -q " \$1=" /proc/cmdline || return 1
955 eval \$2=\$(sed "s/.* \$1=\\\\([^ ]*\\\\).*/\\\\1/" < /proc/cmdline)
956 return 0
957 }
959 copy_rootfs() {
960 total=\$(grep MemTotal /proc/meminfo | sed 's/[^0-9]//g')
961 need=\$(du -c \${path}rootfs* | tail -n 1 | cut -f1)
962 [ \$(( \$total / \$need )) -gt 1 ] || return 1
963 if ! grep -q " keep-loram" /proc/cmdline && cp \${path}rootfs* /mnt; then
964 path=/mnt/
965 return 0
966 else
967 rm -f /mnt/rootfs*
968 return 1
969 fi
970 }
972 echo "Switching / to tmpfs..."
973 mount -t proc proc /proc
974 size="\$(grep rootfssize= < /proc/cmdline | \\
975 sed 's/.*rootfssize=\\([0-9]*[kmg%]\\).*/-o size=\\1/')"
976 [ -n "\$size" ] || size="-o size=90%"
978 while read var default; do
979 eval \$var=\$default
980 getarg \$var \$var
981 done <<EOT
982 eth eth0
983 dns 208.67.222.222,208.67.220.220
984 netmask 255.255.255.0
985 gw
986 ip
987 EOT
988 if [ -n "\$ip" ]; then
989 ifconfig \$eth \$ip netmask \$netmask up
990 route add default gateway \$gw
991 for i in \$(echo \$dns | sed 's/,/ /g'); do
992 echo "nameserver \$i" >> /etc/resolv.conf
993 done
994 else
995 udhcpc -f -q -s /lib/udhcpc -i \$eth
996 fi
997 for i in $urliso ; do
998 [ -n "\$URLISO" ] && URLISO="\$URLISO,"
999 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"
1000 done
1001 getarg urliso URLISO
1002 DIR=fs
1003 if getarg loram DIR; then
1004 DEVICE=\${DIR%,*}
1005 DIR=/\${DIR#*,}
1006 fi
1007 mount -t tmpfs \$size tmpfs /mnt
1008 path2=/mnt/.httpfs/
1009 path=/mnt/.cdrom/
1010 mkdir -p /mnt/.rw /mnt/.wd \$path \$path2
1011 while [ ! -d \$path/boot ]; do
1012 for i in \$(echo \$URLISO | sed 's/,/ /g'); do
1013 httpfs \$i \$path2 && break
1014 done
1015 mount -o loop,ro -t iso9660 \$path2/*.iso \$path
1016 done
1018 memfree=\$(grep MemFree /proc/meminfo | sed 's/[^0-9]//g')
1019 umount /proc
1020 branch=:/mnt/.cdrom/\$DIR
1021 if [ ! -d /mnt/.cdrom/\$DIR/etc ]; then
1022 branch=
1023 for i in \${path}rootfs* ; do
1024 fs=\${i#*root}
1025 branch=\$branch:/mnt/.\$fs
1026 mkdir -p /mnt/.rw/mnt/.\$fs /mnt/.\$fs /mnt/.rw/mnt/.cdrom
1027 insmod /lib/squashfs.ko.gz 2> /dev/null
1028 mount -o loop,ro -t squashfs \${path}root\$fs /mnt/.\$fs
1029 done
1030 else
1031 mkdir -p /mnt/.rw/mnt/.httpfs
1032 fi
1033 while read type opt; do
1034 insmod /lib/\$type.ko.gz && mount -t \$type -o \$opt none /mnt && break
1035 done <<EOT
1036 aufs br=/mnt/.rw\$branch
1037 overlayfs workdir=/mnt/.wd\${branch/:/,lowerdir=},upperdir=/mnt/.rw
1038 EOT
1039 [ -x /bin/httpfs ] && sed -i 's/DHCP="yes"/DHCP="no"/' /mnt/etc/network.conf
1040 [ \$memfree -lt 30000 ] && sed -i 's/ slim//' /mnt/etc/rcS.conf
1041 [ -x /mnt/sbin/init ] && exec /bin/switch_root mnt /sbin/init || sh
1042 EOTEOT
1043 chmod +x $TMP_DIR/initfs/init
1044 for i in $TMP_DIR/initfs/lib/modules/*z ; do
1045 unxz $i || gunzip $i || lzma d $i ${i%.gz}
1046 rm -f $i
1047 gzip -9 ${i%.gz}
1048 done 2>/dev/null
1049 (cd $TMP_DIR/initfs; find | busybox cpio -o -H newc 2>/dev/null) | \
1050 lzma e $TMP_DIR/initfs.gz -si
1051 lzma_set_size $TMP_DIR/initfs.gz
1052 rm -rf $TMP_DIR/initfs
1053 align_to_32bits $TMP_DIR/initfs.gz
1054 return 0
1058 # Move each initramfs to squashfs
1060 build_loram_rootfs() {
1061 rootfs_sizes=""
1062 for i in $TMP_DIR/iso/boot/rootfs*.gz; do
1063 mkdir -p $TMP_DIR/fs
1064 cd $TMP_DIR/fs
1065 (zcat $i 2>/dev/null || unlzma < $i) | cpio -idm
1066 cd - > /dev/null
1067 rootfs=$TMP_DIR/$(basename $i)
1068 /usr/sbin/mksquashfs $TMP_DIR/fs $rootfs -comp xz -Xbcj x86
1069 cd $TMP_DIR
1070 rootfs_sizes="$rootfs_sizes $(( $(du -s $TMP_DIR/fs | cut -f1) - $(du -s $rootfs | cut -f1) ))"
1071 ( cd $(dirname $rootfs); echo $(basename $rootfs) | cpio -o -H newc ) > $rootfs.cpio
1072 rm -f $rootfs
1073 mv $rootfs.cpio $rootfs
1074 cd - > /dev/null
1075 rm -rf $TMP_DIR/fs
1076 done
1080 # Move meta boot configuration files to basic configuration files
1081 # because meta loram flavor is useless when rootfs is not loaded in RAM
1083 unmeta_boot() {
1084 local root=${1:-$TMP_DIR/loramiso}
1085 if [ -f $root/boot/isolinux/noram.cfg ]; then
1086 # We keep enough information to do unloram...
1087 [ -s $root/boot/isolinux/common.cfg ] &&
1088 sed -i 's/label slitaz/label orgslitaz/' \
1089 $root/boot/isolinux/common.cfg
1090 set -- $(grep 'append ifmem [0-9]' $root/boot/isolinux/isolinux.cfg)
1091 shift
1092 sed -i '/ifmem/{NNNNNNNNd};/^LABEL/{N;/LABEL SliTaz [^L]/{NNNd}}' \
1093 $root/boot/isolinux/isolinux.cfg
1094 [ -n "$3" ] || set -- $(grep 'append [0-9]' $root/boot/isolinux/common.cfg)
1095 sed -i "s/label $3\$/label slitaz/;s|=/boot/rootfs\(.*\).gz |=/boot/rootfs.gz |" \
1096 $root/boot/isolinux/*.cfg
1097 fi
1101 # Move rootfs to squashfs filesystem(s) to the cdrom writeable with aufs/overlayfs.
1102 # These squashfs may be loaded in RAM at boot time.
1103 # Rootfs are also copied to CD-ROM for tiny ramsize systems.
1104 # Meta flavors are converted to normal flavors.
1106 build_loram_cdrom() {
1107 build_initfs cdrom || return 1
1108 cp -a $TMP_DIR/iso $TMP_DIR/loramiso
1109 mkdir $TMP_DIR/loramiso/fs
1110 cd $TMP_DIR/loramiso/fs
1111 for i in $( ls ../boot/root* | sort -r ) ; do
1112 (zcat $i 2>/dev/null || unlzma < $i) | cpio -idmu
1113 rm -f $i
1114 done
1115 mkdir -p $TMP_DIR/loramiso/fs/mnt/.cdrom
1116 cd - >/dev/null
1117 mv $TMP_DIR/initfs.gz $TMP_DIR/loramiso/boot/rootfs.gz
1118 unmeta_boot
1119 VOLUM_NAME="SliTaz_LoRAM_CDROM"
1120 sed -i "s|root=|isofs= rodev=/dev/cdrom/fs &|;s/.ive/cdrom/" \
1121 $TMP_DIR/loramiso/boot/isolinux/*.cfg
1122 create_iso $OUTPUT $TMP_DIR/loramiso
1126 # Create http bootstrap to load and remove loram_cdrom
1127 # Meta flavors are converted to normal flavors.
1129 build_loram_http() {
1130 build_initfs http || return 1
1131 cp -a $TMP_DIR/iso $TMP_DIR/loramiso
1132 rm -f $TMP_DIR/loramiso/boot/rootfs*
1133 mv $TMP_DIR/initfs.gz $TMP_DIR/loramiso/boot/rootfs.gz
1134 unmeta_boot
1135 create_iso $OUTPUT $TMP_DIR/loramiso
1139 # Update meta flavor selection sizes.
1140 # Reduce sizes with rootfs gains.
1142 update_metaiso_sizes() {
1143 for cfg in $(grep -El '(append|ifmem) [0-9]' $TMP_DIR/loramiso/boot/isolinux/*.cfg)
1144 do
1145 local append="$(grep -E '(append|ifmem) [0-9]' $cfg)"
1146 local sizes="$rootfs_sizes"
1147 local new
1148 set -- $append
1149 shift
1150 [ "$1" == "ifmem" ] && shift
1151 new=""
1152 while [ -n "$2" ]; do
1153 local s
1154 case "$1" in
1155 *G) s=$(( ${1%G} * 1024 * 1024 ));;
1156 *M) s=$(( ${1%M} * 1024 ));;
1157 *) s=${1%K};;
1158 esac
1159 sizes=${sizes#* }
1160 for i in $sizes ; do
1161 s=$(( $s - $i ))
1162 done
1163 new="$new $s $2"
1164 shift 2
1165 done
1166 sed -i -e "/append [0-9]/s/append .*/append$new $1/" -e \
1167 "/append ifmem [0-9]/s/append .*/append ifmem$new $1/" $cfg
1168 sed -i 's|\(initrd=\)\(/boot/rootfs.\.gz\)|\1/boot/rootfs.gz,\2|' $cfg
1169 sed -i '/LABEL base/{NNNNp;s|base .ive|cdrom|;s|base|cdrom|;s|,[^ ]*||}' $cfg
1170 done
1174 # Move rootfs to a squashfs filesystem into the initramfs writeable with aufs/overlayfs.
1175 # Meta flavor selection sizes are updated.
1177 build_loram_ram() {
1178 build_initfs ram || return 1
1179 build_loram_rootfs
1180 cp -a $TMP_DIR/iso $TMP_DIR/loramiso
1181 make_bzImage_hardlink $TMP_DIR/loramiso/boot
1182 mv $TMP_DIR/initfs.gz $TMP_DIR/loramiso/boot/rootfs.gz
1183 cp $TMP_DIR/rootfs* $TMP_DIR/loramiso/boot
1184 update_metaiso_sizes
1185 create_iso $OUTPUT $TMP_DIR/loramiso
1189 # Remove files installed by packages
1191 find_flavor_rootfs() {
1192 for i in $1/etc/tazlito/*.extract; do
1193 [ -e $i ] || continue
1194 chroot $1 /bin/sh ${i#$1}
1195 done
1197 # Clean hardlinks and files patched by genisofs in /boot
1198 for i in isolinux/isolinux.bin isolinux/boot.cat bzImage ; do
1199 rm -f $1/boot/$i*
1200 done
1202 # Clean files generated in post_install
1203 rm -f $1/lib/modules/*/modules.* $1/etc/mtab \
1204 $1/dev/core $1/dev/fd $1/dev/std*
1206 # Verify md5
1207 cat $1$INSTALLED/*/md5sum | \
1208 while read md5 file; do
1209 [ -e "$1$file" ] || continue
1210 [ "$(md5sum < "$1$file")" == "$md5 -" ] &&
1211 rm -f "$1$file"
1212 done
1214 # Check configuration files
1215 for i in $1$INSTALLED/*/volatile.cpio.gz; do
1216 [ -e $i ] || continue
1217 mkdir /tmp/volatile$$
1218 zcat $i | ( cd /tmp/volatile$$ ; cpio -idmu > /dev/null 2>&1 )
1219 ( cd /tmp/volatile$$ ; find * -type f 2> /dev/null) | \
1220 while read file ; do
1221 [ -e "$1/$file" ] || continue
1222 cmp -s "/tmp/volatile$$/$file" "$1/$file" && rm -f "$1/$file"
1223 done
1224 rm -rf /tmp/volatile$$
1225 done
1227 # Remove other files blindly
1228 for i in $1$INSTALLED/*/files.list; do
1229 for file in $(cat "$i"); do
1230 [ "$1$file" -nt "$i" ] && continue
1231 [ -f "$1$file" -a ! -L "$1$file" ] && continue
1232 [ -d "$1$file" ] || rm -f "$1$file"
1233 done
1234 done
1236 # Remove tazpkg files and tmp files
1237 rm -rf $1$INSTALLED* $1/tmp $1/var/tmp
1238 rm -f $1$LOCALSTATE/*packages* $1$LOCALSTATE/files.list.lzma \
1239 $1$LOCALSTATE/mirror* $1/var/cache/*/* \
1240 $1/var/lock/* $1/var/log/* $1/var/run/* $1/var/run/*/* \
1241 $1/var/lib/* $1/var/lib/dbus/* 2>/dev/null
1243 # Cleanup directory tree
1244 cd $1
1245 find * -type d | sort -r | while read dir; do
1246 rmdir "$dir" 2>/dev/null
1247 done
1248 cd - > /dev/null
1252 # Get byte(s) from a binary file
1254 get() {
1255 od -v -j $1 -N ${3:-2} -t u${3:-2} -w${3:-2} -An $2 2>/dev/null
1259 # Get cpio flavor info from the ISO image
1261 flavordata() {
1262 [ $(get 1024 $1) -eq 35615 ] && n=2 || n=$((1+$(get 417 $1 1)))
1263 dd if=$1 bs=512 skip=$n count=20 2>/dev/null | zcat 2>/dev/null
1267 # Restore undigest mirrors
1269 restore_mirrors() {
1270 local undigest="$root$LOCALSTATE/undigest" priority="$root$LOCALSTATE/priority"
1271 [ -d "$undigest.bak" ] || [ -e "$priority.bak" ] || return
1273 action 'Restoring mirrors...'
1274 if [ -d "$undigest.bak" ]; then
1275 [ -d "$undigest" ] && rm -r "$undigest"
1276 mv "$undigest.bak" "$undigest"
1277 fi
1278 [ -e "$priority.bak" ] && mv -f "$priority.bak" "$priority"
1279 :; status
1283 # Setup undigest mirrors
1285 setup_mirrors() {
1286 # Setup mirrors in plain system or in chroot (with variable root=)
1288 # Note, difficulties exists in using local-filesystem-mirrors (when content
1289 # of the 'mirror' file is point to folder somewhere in the FS) inside chroot,
1290 # because mirror should be in the chroot too. We make local mirrors to be
1291 # accessible via http://localhost/... using built-in SliTaz web server.
1292 local mirrorlist="$1" fresh repacked
1293 local undigest="$root$LOCALSTATE/undigest" priority="$root$LOCALSTATE/priority"
1295 # Restore mirrors first: in case of non-clear exits, hangs, etc.
1296 restore_mirrors
1298 _ 'Setting up mirrors for %s...' "$root/"
1299 # Backing up current undigest mirrors and priority
1300 [ -d "$undigest" ] && mv "$undigest" "$undigest.bak"
1301 [ -e "$priority" ] && mv "$priority" "$priority.bak"
1302 rm -rf '/var/www/tazlito/'
1303 mkdir -p '/var/www/tazlito/'
1305 # Packages produced by CookUtils: on Tank or local, or repacked packages: highest priority
1306 fresh='/home/slitaz/packages'
1307 if [ -d "$fresh" ]; then
1308 # Make this mirror accessible using http://localhost/tazlito/fresh
1309 ln -s "$fresh" '/var/www/tazlito/fresh'
1310 # Setup first undigest mirror
1311 mkdir -p "$undigest/fresh"
1312 echo "http://localhost/tazlito/fresh/" > "$undigest/fresh/mirror"
1313 echo 'fresh' >> "$priority"
1314 # Rebuild mirror DB if needed
1315 [ ! -e "$fresh/IDs" ] && tazpkg mkdb "$fresh" --forced --root=''
1316 [ -n "$(find -L "$fresh" -name '*.tazpkg' -newer "$fresh/IDs")" ] && \
1317 tazpkg mkdb "$fresh" --forced --root=''
1318 cp -a "$fresh/files.list.lzma" "$fresh/files-list.lzma"
1319 fi
1321 # Repacked packages: high priority
1322 repacked="$PACKAGES_REPOSITORY"
1323 if [ -d "$repacked" -a "$repacked" != "$fresh" ] && ls "$repacked" | grep -q ".tazpkg"; then
1324 # According to Tazlito setup file (tazlito.conf):
1325 # WORK_DIR="/home/slitaz/$SLITAZ_VERSION"
1326 # or
1327 # WORK_DIR="/home/slitaz"
1328 # and
1329 # PACKAGES_REPOSITORY="$WORK_DIR/packages"
1330 # It MAY or MAY NOT match /home/slitaz/packages, so here we setup second repository
1332 # Make this mirror accessible using http://localhost/tazlito/repacked
1333 ln -s "$repacked" '/var/www/tazlito/repacked'
1334 # Setup second undigest mirror
1335 mkdir -p "$undigest/repacked"
1336 echo "http://localhost/tazlito/repacked/" > "$undigest/repacked/mirror"
1337 echo 'repacked' >> "$priority"
1338 # Rebuild mirror DB if needed
1339 [ ! -e "$repacked/IDs" ] && tazpkg mkdb "$repacked" --forced --root=''
1340 [ -n "$(find -L "$repacked" -name '*.tazpkg' -newer "$repacked/IDs")" ] && \
1341 tazpkg mkdb "$repacked" --forced --root=''
1342 cp -a "$repacked/files.list.lzma" "$repacked/files-list.lzma"
1343 fi
1345 # All repositories listed in mirrors list: normal priority
1346 [ -e "$mirrorlist" ] && \
1347 while read mirror; do
1348 # Provide consistent mirror ID for caching purpose: /var/cache/tazpkg/<mirror ID>/packages
1349 mirrorid=$(echo "$mirror" | md5sum | cut -d' ' -f1)
1350 mkdir -p "$undigest/$mirrorid"
1351 echo "$mirror" > "$undigest/$mirrorid/mirror"
1352 echo "$mirrorid" >> "$priority"
1353 done < "$mirrorlist"
1355 # And, finally, main mirror with the lowest (failsafe) priority (nothing to do)
1357 # Show list of mirrors
1358 awk -vdb="$root$LOCALSTATE" '
1359 function show(num, name, url, pad, len) {
1360 pad = "................................";
1361 len = (32 - length(name));
1362 printf " %-1.1d. %s%*.*s %-44.44s\n", num, name, len, len, pad, url;
1365 num++;
1366 "cat " db "/undigest/" $0 "/mirror" | getline url;
1367 show(num, $0, url);
1369 END {
1370 num++;
1371 "cat " db "/mirror" | getline url;
1372 show(num, "main", url);
1373 }' "$priority"
1375 tazpkg recharge --quiet
1379 # Get list of 'packages.info' lists using priority
1381 pi_lists() {
1382 local pi
1383 [ -s "$root$LOCALSTATE/packages.info" ] || tazpkg recharge >/dev/null 2>&1
1384 local priority="$root$LOCALSTATE/priority"
1385 local undigest="$root$LOCALSTATE/undigest"
1388 [ -s "$priority" ] && cat "$priority"
1389 echo 'main'
1390 [ -d "$undigest" ] && ls "$undigest"
1391 } | awk -vun="$undigest/" '
1393 if (arr[$0] != 1) {
1394 arr[$0] = 1;
1395 print un $0 "/packages.info";
1397 }' | sed 's|/undigest/main||' | \
1398 while read pi; do
1399 [ -e "$pi" ] && echo "$pi"
1400 done
1404 # Strip versions from packages list
1406 strip_versions() {
1407 action 'Strip versions from list %s...' "$(basename "$1")"
1408 local in_list="$1" tmp_list="$(mktemp)" namever pkg
1409 [ -f "$in_list" ] || die "List '$in_list' not found."
1411 # $pkg=<name>-<version> or $pkg=<name>; both <name> and <version> may contain dashes
1412 awk '
1414 if (FILENAME ~ "packages.info") {
1415 # Collect package names
1416 FS = "\t"; pkg[$1] = 1;
1417 } else {
1418 FS = "-"; OFS = "-"; $0 = $0; # Fix bug with FS for first record
1419 while (NF > 1 && ! pkg[$0])
1420 NF --;
1421 printf "%s\n", $0;
1423 }' $(pi_lists) "$in_list" > "$tmp_list"
1425 cat "$tmp_list" > "$in_list"
1426 rm "$tmp_list"
1427 status
1431 # Calculate sizes (estimated) and real packages number (including all dependencies)
1432 # using given extracted flavor and current mirrors.
1434 # Input: <unpacked flavor dir> <flavor name> [<output full list file>]
1435 # Output in human readable form:
1436 # <unpacked size> <packed size> <size of ISO> <number of packages>
1437 # File $1/err output: unknown packages
1438 # File $1/warn output: warnings about missing packages
1439 # TODO: use 'equivalent packages' rules
1441 calc_sizes() {
1442 local dir="$1" flavor="$2" outfile="$3"
1443 local rootfs_packed=0 rootfs_unpacked=0 rootcd_unpacked=0
1445 if [ -s "$dir/$flavor.rootfs" ]; then
1446 rootfs_packed="$(wc -c < "$dir/$flavor.rootfs")";
1447 rootfs_unpacked="$(zcat "$dir/$flavor.rootfs" | wc -c)";
1448 fi
1449 if [ -s "$dir/$flavor.rootcd" ]; then
1450 rootcd_unpacked="$(zcat "$dir/$flavor.rootcd" | wc -c)";
1451 fi
1453 awk -F$'\t' \
1454 -vrootfs_p="$rootfs_packed" -vrootfs_u="$rootfs_unpacked" -vrootcd_u="$rootcd_unpacked" \
1455 -voutfile="$outfile" -verrfile="$dir/err" -vwarnfile="$dir/warn" '
1456 BEGIN {
1457 K = 1024; M = K * 1024; G = M * 1024;
1459 function h2b(h) {
1460 # Convert human-readable format to bytes
1461 if (h ~ "K") return h * K;
1462 if (h ~ "M") return h * M;
1463 if (h ~ "G") return h * G;
1464 return h;
1466 function b2h(b, p) {
1467 # Convert bytes to human-readable format
1468 if (b >= G) { b /= G; p = "G"; }
1469 else if (b >= M) { b /= M; p = "M"; }
1470 else { b /= K; p = "K"; }
1471 if (b >= 100) printf "%d%s\n", b, p;
1472 else printf "%.1f%s\n", b, p;
1474 function mark_deps(pkg, localdepend, localdepends) {
1475 # Mark package with its dependencies (to be processed later)
1476 if (sizes[pkg]) {
1477 if (! pkgs[pkg]) {
1478 pkgs[pkg] = sizes[pkg];
1480 if (depends[pkg]) {
1481 split(depends[pkg], localdepends, " ");
1482 # Recursive call
1483 for (localdepend in localdepends)
1484 mark_deps(localdepends[localdepend]);
1487 } else {
1488 printf " %s\n", $1 >> errfile;
1491 function calc(pkg, size_u, size_p) {
1492 # Calculate unpacked and packed sizes of /boot
1493 if (pkgs[pkg]) { boot_u += h2b(size_u); boot_p += h2b(size_p); }
1495 # main loop
1497 if (FILENAME ~ "packages.info") {
1498 # Step #1: fill arrays "sizes" and "depends"
1499 if (! sizes[$1]) {
1500 sizes[$1] = $7;
1501 depends[$1] = $8;
1503 } else {
1504 # Step #2: mark packages and its dependencies
1505 mark_deps($1);
1508 END {
1509 # Calculate sums for all marked packages and its deps
1510 for (pkg in pkgs) {
1511 num_pkgs ++;
1512 split(pkgs[pkg], s, " ");
1513 size_packed += h2b(s[1]);
1514 size_unpacked += h2b(s[2]);
1515 if (outfile) print pkg >> outfile;
1517 # Add files placed in flavor.rootfs
1518 size_packed += rootfs_p;
1519 size_unpacked += rootfs_u;
1521 # Check critical packages: "syslinux" and one of the packages containing "vmlinuz*"
1522 printf "" > warnfile;
1523 if (! pkgs["syslinux"]) printf " * Syslinux\n" >> warnfile;
1524 if (! pkgs["linux"] && ! pkgs["linux-without-modules"] && \
1525 ! pkgs["linux64"] && ! pkgs["linux64-without-modules"] && \
1526 ! pkgs["linux-libre"] && ! pkgs["linux-libre-without-modules"] && \
1527 ! pkgs["linux-uml"]) printf " * Linux kernel\n" >> warnfile;
1529 # Calculate unpacked and packed sizes of /boot
1530 calc("syslinux", "156K", "120K" );
1531 calc("gpxe", "196K", "188K" );
1532 calc("ipxe", "316K", "312K" );
1533 calc("memtest", "52K", "48K" );
1534 calc("memtest-serial", "52K", "48K" );
1535 calc("slitaz-configs-base", "36K", "28K" );
1536 calc("linux", "2.8M", "2.8M" );
1537 calc("linux-without-modules", "12.6M", "12.8M");
1538 calc("linux64", "3.0M", "3.0M" );
1539 calc("linux64-without-modules", "13.2M", "13.4M");
1540 calc("linux-libre", "2.3M", "2.3M" );
1541 calc("linux-libre-without-modules", "6.9M", "6.9M" );
1542 calc("linux-uml", "3.0M", "1.1M" );
1544 # /boot is moved away from rootfs
1545 size_packed -= boot_p;
1546 size_unpacked -= boot_u;
1548 # Add rootcd payload and /boot content sizes
1549 size_iso = size_packed + rootcd_u + boot_u;
1551 printf "%s %s ", b2h(size_unpacked), b2h(size_packed);
1552 printf "%s %d\n", b2h(size_iso), num_pkgs;
1553 }' $(pi_lists) "$dir/$flavor.pkglist"
1557 # Display list of unknown packages (informative)
1558 display_unknown() {
1559 [ -s "$1" ] || return
1560 echo "Unknown packages:" >&2
1561 cat "$1" >&2
1562 rm "$1"
1566 # Display warnings about critical packages absent (informative)
1567 display_warn() {
1568 [ -s "$1" ] || return
1569 echo "Absent critical packages:" >&2
1570 cat "$1" >&2
1571 rm "$1"
1572 echo "Probably ISO image will be unusable."
1578 ####################
1579 # Tazlito commands #
1580 ####################
1582 # /usr/bin/tazlito is linked with /usr/bin/reduplicate and /usr/bin/deduplicate
1583 case "$0" in
1584 *reduplicate)
1585 find ${@:-.} ! -type d -links +1 \
1586 -exec cp -a {} {}$$ \; -exec mv {}$$ {} \;
1587 exit 0 ;;
1588 *deduplicate)
1589 deduplicate "$@"
1590 exit 0 ;;
1591 esac
1594 case "$COMMAND" in
1595 stats)
1596 # Tazlito general statistics from the config file.
1598 title 'Tazlito statistics'
1599 optlist "\
1600 Config file : $CONFIG_FILE
1601 ISO name : $ISO_NAME.iso
1602 Volume name : $VOLUM_NAME
1603 Prepared : $PREPARED
1604 Packages repository : $PACKAGES_REPOSITORY
1605 Distro directory : $DISTRO
1606 Additional files : $ADDFILES
1607 " | sed '/: $/d'
1608 footer
1609 ;;
1612 list-addfiles)
1613 # Simple list of additional files in the rootfs
1614 newline
1615 if [ -d "$ADDFILES/rootfs" ]; then
1616 cd $ADDFILES
1617 find rootfs -type f
1618 else
1619 _ 'Additional files not found: %s' "$ADDFILES/rootfs/"
1620 fi
1621 newline
1622 ;;
1625 gen-config)
1626 # Generate a new config file in the current dir or the specified
1627 # directory by $2.
1629 if [ -n "$2" ]; then
1630 mkdir -p "$2" && cd "$2"
1631 fi
1633 newline
1634 action 'Generating empty tazlito.conf...'
1635 empty_config_file
1636 status
1638 separator
1639 if [ -f 'tazlito.conf' ] ; then
1640 _ 'Configuration file is ready to edit.'
1641 _ 'File location: %s' "$(pwd)/tazlito.conf"
1642 newline
1643 fi
1644 ;;
1647 configure)
1648 # Configure a tazlito.conf config file. Start by getting
1649 # a empty config file and sed it.
1651 if [ -f 'tazlito.conf' ]; then
1652 rm tazlito.conf
1653 else
1654 [ $(id -u) -ne 0 ] && die 'You must be root to configure the main config file' \
1655 'or in the same directory of the file you want to configure.'
1656 cd /etc
1657 fi
1659 empty_config_file
1661 title 'Configuring: %s' "$(pwd)/tazlito.conf"
1663 # ISO name.
1664 echo -n "ISO name : " ; read answer
1665 sed -i s#'ISO_NAME=\"\"'#"ISO_NAME=\"$answer\""# tazlito.conf
1666 # Volume name.
1667 echo -n "Volume name : " ; read answer
1668 sed -i s/'VOLUM_NAME=\"SliTaz\"'/"VOLUM_NAME=\"$answer\""/ tazlito.conf
1669 # Packages repository.
1670 echo -n "Packages repository : " ; read answer
1671 sed -i s#'PACKAGES_REPOSITORY=\"\"'#"PACKAGES_REPOSITORY=\"$answer\""# tazlito.conf
1672 # Distro path.
1673 echo -n "Distro path : " ; read answer
1674 sed -i s#'DISTRO=\"\"'#"DISTRO=\"$answer\""# tazlito.conf
1675 footer "Config file is ready to use."
1676 echo 'You can now extract an ISO or generate a distro.'
1677 newline
1678 ;;
1681 gen-iso)
1682 # Simply generate a new iso.
1684 check_root
1685 verify_rootcd
1686 gen_livecd_isolinux
1687 distro_stats
1688 ;;
1691 gen-initiso)
1692 # Simply generate a new initramfs with a new iso.
1694 check_root
1695 verify_rootcd
1696 gen_initramfs "$ROOTFS"
1697 gen_livecd_isolinux
1698 distro_stats
1699 ;;
1702 extract-distro)
1703 # Extract an ISO image to a directory and rebuild the LiveCD tree.
1705 check_root
1706 ISO_IMAGE="$2"
1707 [ -z "$ISO_IMAGE" ] && die 'Please specify the path to the ISO image.' \
1708 'Example:\n tazlito image.iso /path/target'
1710 # Set the distro path by checking for $3 on cmdline.
1711 TARGET="${3:-$DISTRO}"
1713 # Exit if existing distro is found.
1714 [ -d "$TARGET/rootfs" ] && die "A rootfs exists in '$TARGET'." \
1715 'Please clean the distro tree or change directory path.'
1717 title 'Tazlito extracting: %s' "$(basename $ISO_IMAGE)"
1719 # Start to mount the ISO.
1720 action 'Mounting ISO image...'
1721 mkdir -p "$TMP_DIR"
1722 # Get ISO file size.
1723 isosize=$(du -sh "$ISO_IMAGE" | cut -f1)
1724 mount -o loop -r "$ISO_IMAGE" "$TMP_DIR"
1725 sleep 2
1726 # Prepare target dir, copy the kernel and the rootfs.
1727 mkdir -p "$TARGET/rootfs" "$TARGET/rootcd/boot"
1728 status
1730 action 'Copying the Linux kernel...'
1731 if cp $TMP_DIR/boot/vmlinuz* "$TARGET/rootcd/boot" 2>/dev/null; then
1732 make_bzImage_hardlink "$TARGET/rootcd/boot"
1733 else
1734 cp "$TMP_DIR/boot/bzImage" "$TARGET/rootcd/boot"
1735 fi
1736 status
1738 for i in $(ls $TMP_DIR); do
1739 [ "$i" == 'boot' ] && continue
1740 cp -a "$TMP_DIR/$i" "$TARGET/rootcd"
1741 done
1743 for loader in isolinux syslinux extlinux grub; do
1744 [ -d "$TMP_DIR/boot/$loader" ] || continue
1745 action 'Copying %s files...' "$loader"
1746 cp -a "$TMP_DIR/boot/$loader" "$TARGET/rootcd/boot"
1747 status
1748 done
1750 action 'Copying the rootfs...'
1751 cp $TMP_DIR/boot/rootfs.?z "$TARGET/rootcd/boot"
1752 status
1754 # Extract initramfs.
1755 cd "$TARGET/rootfs"
1756 action 'Extracting the rootfs...'
1757 extract_rootfs "$TARGET/rootcd/boot/$INITRAMFS" "$TARGET/rootfs"
1758 # unpack /usr
1759 for i in etc/tazlito/*.extract; do
1760 [ -f "$i" ] && . $i ../rootcd
1761 done
1762 # Umount and remove temp directory and cd to $TARGET to get stats.
1763 umount "$TMP_DIR" && rm -rf "$TMP_DIR"
1764 cd ..
1765 status
1767 newline
1768 separator
1769 echo "Extracted : $(basename $ISO_IMAGE) ($isosize)"
1770 echo "Distro tree : $(pwd)"
1771 echo "Rootfs size : $(du -sh rootfs)"
1772 echo "Rootcd size : $(du -sh rootcd)"
1773 footer
1774 ;;
1777 list-flavors)
1778 # Show available flavors.
1779 local list='/etc/tazlito/flavors.list'
1780 [ ! -s $list -o -n "$recharge" ] && download flavors.list -O - > $list
1781 title 'List of flavors'
1782 cat $list
1783 footer
1784 ;;
1787 show-flavor)
1788 # Show flavor description.
1789 set -e
1790 flavor=${2%.flavor}
1791 flv_dir="$(extract_flavor "$flavor")"
1792 desc="$flv_dir/$flavor.desc"
1793 if [ -n "$brief" ]; then
1794 if [ -z "$noheader" ]; then
1795 printf "%-16.16s %6.6s %6.6s %s\n" 'Name' 'ISO' 'Rootfs' 'Description'
1796 separator
1797 fi
1798 printf "%-16.16s %6.6s %6.6s %s\n" "$flavor" \
1799 "$(field ISO "$desc")" \
1800 "$(field Rootfs "$desc")" \
1801 "$(field Description "$desc")"
1802 else
1803 separator
1804 cat "$desc"
1805 fi
1806 cleanup
1807 ;;
1810 gen-liveflavor)
1811 # Generate a new flavor from the live system.
1812 FLAVOR=${2%.flavor}
1813 [ -z "$FLAVOR" ] && die 'Please specify flavor name on the commandline.'
1815 case "$FLAVOR" in
1816 -?|-h*|--help)
1817 cat <<EOT
1818 SliTaz Live Tool - Version: $VERSION
1820 $(boldify 'Usage:') tazlito gen-liveflavor <flavor-name> [<flavor-patch-file>]
1822 $(boldify '<flavor-patch-file> format:')
1823 $(optlist "\
1824 code data
1825 + package to add
1826 - package to remove
1827 ! non-free package to add
1828 ? display message
1829 @ flavor description
1830 ")
1832 $(boldify 'Example:')
1833 $(optlist "\
1834 @ Developer tools for SliTaz maintainers
1835 + slitaz-toolchain
1836 + mercurial
1837 ")
1838 EOT
1839 exit 1
1840 ;;
1841 esac
1842 mv /etc/tazlito/distro-packages.list \
1843 /etc/tazlito/distro-packages.list.$$ 2>/dev/null
1844 rm -f distro-packages.list non-free.list 2>/dev/null
1845 tazpkg recharge
1847 DESC=""
1848 [ -n "$3" ] && \
1849 while read action pkg; do
1850 case "$action" in
1851 +) yes | tazpkg get-install $pkg 2>&1 >> $log || exit 1 ;;
1852 -) yes | tazpkg remove $pkg ;;
1853 !) echo $pkg >> non-free.list ;;
1854 @) DESC="$pkg" ;;
1855 \?) echo -en "$pkg"; read action ;;
1856 esac
1857 done < $3
1859 yes '' | tazlito gen-distro
1860 echo "$DESC" | tazlito gen-flavor "$FLAVOR"
1861 mv /etc/tazlito/distro-packages.list.$$ \
1862 /etc/tazlito/distro-packages.list 2>/dev/null
1863 ;;
1866 gen-flavor)
1867 # Generate a new flavor from the last ISO image generated
1868 FLAVOR=${2%.flavor}
1869 [ -z "$FLAVOR" ] && die 'Please specify flavor name on the commandline.'
1871 title 'Flavor generation'
1872 check_rootfs
1873 FILES="$FLAVOR.pkglist"
1875 action 'Creating file %s...' "$FLAVOR.flavor"
1876 for i in rootcd rootfs; do
1877 if [ -d "$ADDFILES/$i" ] ; then
1878 FILES="$FILES\n$FLAVOR.$i"
1879 (cd "$ADDFILES/$i"; find . | cpio -o -H newc 2>/dev/null | gzip -9) > $FLAVOR.$i
1880 fi
1881 done
1882 status
1884 answer=$(grep -s ^Description $FLAVOR.desc)
1885 answer=${answer#Description : }
1886 if [ -z "$answer" ]; then
1887 echo -n "Description: "
1888 read answer
1889 fi
1891 action 'Compressing flavor %s...' "$FLAVOR"
1892 echo "Flavor : $FLAVOR" > $FLAVOR.desc
1893 echo "Description : $answer" >> $FLAVOR.desc
1894 (cd $DISTRO; distro_sizes) >> $FLAVOR.desc
1895 \rm -f $FLAVOR.pkglist $FLAVOR.nonfree 2>/dev/null
1896 for i in $(ls $ROOTFS$INSTALLED); do
1897 eval $(grep ^VERSION= $ROOTFS$INSTALLED/$i/receipt)
1898 EXTRAVERSION=""
1899 eval $(grep ^EXTRAVERSION= $ROOTFS$INSTALLED/$i/receipt)
1900 eval $(grep ^CATEGORY= $ROOTFS$INSTALLED/$i/receipt)
1901 if [ "$CATEGORY" == 'non-free' -a "${i%%-*}" != 'get' ]; then
1902 echo "$i" >> $FLAVOR.nonfree
1903 else
1904 echo "$i-$VERSION$EXTRAVERSION" >> $FLAVOR.pkglist
1905 fi
1906 done
1907 [ -s $FLAVOR.nonfree ] && $FILES="$FILES\n$FLAVOR.nonfree"
1908 for i in $LOCALSTATE/undigest/*/mirror ; do
1909 [ -s $i ] && cat $i >> $FLAVOR.mirrors
1910 done
1911 [ -s $FLAVOR.mirrors ] && $FILES="$FILES\n$FLAVOR.mirrors"
1912 echo -e "$FLAVOR.desc\n$FILES" | cpio -o -H newc 2>/dev/null | gzip -9 > $FLAVOR.flavor
1913 rm $(echo -e $FILES)
1914 status
1916 footer "Flavor size: $(du -sh $FLAVOR.flavor)"
1917 ;;
1920 upgrade-flavor)
1921 # Strip versions from pkglist and update estimated numbers in flavor.desc
1922 flavor="${2%.flavor}"
1923 set -e
1924 [ -f "$flavor.flavor" ] || download "$flavor.flavor"
1925 set +e
1927 flv_dir="$(extract_flavor "$flavor")"
1929 strip_versions "$flv_dir/$flavor.pkglist"
1931 action 'Updating %s...' "$flavor.desc"
1933 [ -f "$flv_dir/$flavor.mirrors" ] && setup_mirrors "$flv_dir/$flavor.mirrors" >/dev/null
1934 set -- $(calc_sizes "$flv_dir" "$flavor")
1935 restore_mirrors >/dev/null
1937 sed -i -e '/Image is ready/d' \
1938 -e "s|\(Rootfs size *:\).*$|\1 $1 (estimated)|" \
1939 -e "s|\(Initramfs size *:\).*$|\1 $2 (estimated)|" \
1940 -e "s|\(ISO image size *:\).*$|\1 $3 (estimated)|" \
1941 -e "s|\(Packages *:\).*$|\1 $4|" \
1942 -e "s|\(Build date *:\).*$|\1 $(date '+%Y%m%d at %T')|" \
1943 "$flv_dir/$flavor.desc"
1945 pack_flavor "$flv_dir" "$flavor"
1946 status
1947 display_unknown "$flv_dir/err"
1948 display_warn "$flv_dir/warn"
1949 cleanup
1950 ;;
1953 extract-flavor)
1954 # Extract a flavor into $FLAVORS_REPOSITORY
1955 flavor="${2%.flavor}"
1956 set -e
1957 [ -f "$flavor.flavor" ] || download "$flavor.flavor"
1958 set +e
1960 action 'Extracting %s...' "$flavor.flavor"
1961 flv_dir="$(extract_flavor "$flavor" full)"
1962 storage="$FLAVORS_REPOSITORY/$flavor"
1964 rm -rf "$storage" 2>/dev/null
1965 mkdir -p "$storage"
1966 cp -a "$flv_dir"/* "$storage"
1967 rm "$storage/description"
1968 status
1970 strip_versions "$storage/packages.list"
1972 cleanup
1973 ;;
1976 pack-flavor)
1977 # Create a flavor from $FLAVORS_REPOSITORY.
1978 flavor=${2%.flavor}
1979 storage="$FLAVORS_REPOSITORY/$flavor"
1981 [ -s "$storage/receipt" ] || die "No $flavor receipt in $FLAVORS_REPOSITORY."
1983 action 'Creating flavor %s...' "$flavor"
1984 tmp_dir="$(mktemp -d)"
1986 while read from to; do
1987 [ -s "$storage/$from" ] || continue
1988 cp -a "$storage/$from" "$tmp_dir/$to"
1989 done <<EOT
1990 mirrors $flavor.mirrors
1991 distro.sh $flavor-distro.sh
1992 receipt $flavor.receipt
1993 non-free.list $flavor.nonfree
1994 EOT
1996 # Build the package list.
1997 # It can include a list from another flavor with the keyword @include
1998 if [ -s "$storage/packages.list" ]; then
1999 include=$(grep '^@include' "$storage/packages.list")
2000 if [ -n "$include" ]; then
2001 include=${include#@include }
2002 if [ -s "$FLAVORS_REPOSITORY/$include/packages.list" ]; then
2003 cp -f "$FLAVORS_REPOSITORY/$include/packages.list" "$tmp_dir/$flavor.pkglist"
2004 else
2005 echo -e "\nERROR: Can't find include package list from $include\n"
2006 fi
2007 fi
2008 # Generate the final/initial package list
2009 [ -s "$storage/packages.list" ] && \
2010 cat "$storage/packages.list" >> "$tmp_dir/$flavor.pkglist"
2011 sed -i '/@include/d' "$tmp_dir/$flavor.pkglist"
2012 fi
2014 if grep -q ^ROOTFS_SELECTION "$storage/receipt"; then
2015 # Process multi-rootfs flavor
2016 . "$storage/receipt"
2017 set -- $ROOTFS_SELECTION
2018 [ -n "$FRUGAL_RAM" ] || FRUGAL_RAM=$1
2019 [ -f "$FLAVORS_REPOSITORY/$2/packages.list" ] || tazlito extract-flavor $2
2020 cp "$FLAVORS_REPOSITORY/$2/packages.list" "$tmp_dir/$flavor.pkglist"
2022 for i in rootcd rootfs; do
2023 mkdir "$tmp_dir/$i"
2024 # Copy extra files from the first flavor
2025 [ -d "$FLAVORS_REPOSITORY/$2/$i" ] &&
2026 cp -a "$FLAVORS_REPOSITORY/$2/$i" "$tmp_dir"
2027 # Overload extra files by meta flavor
2028 [ -d "$storage/$i" ] && cp -a "$storage/$i" "$tmp_dir"
2029 [ -n "$(ls $tmp_dir/$i)" ] &&
2030 (cd "$tmp_dir/$i"; find . | cpio -o -H newc 2>/dev/null ) | \
2031 gzip -9 > "$tmp_dir/$flavor.$i"
2032 rm -rf "$tmp_dir/$i"
2033 done
2034 else
2035 # Process plain flavor
2036 for i in rootcd rootfs; do
2037 [ -d "$storage/$i" ] || continue
2038 (cd "$storage/$i";
2039 find . | cpio -o -H newc 2>/dev/null) | gzip -9 > "$tmp_dir/$flavor.$i"
2040 done
2041 fi
2043 unset VERSION MAINTAINER ROOTFS_SELECTION
2044 set -- $(calc_sizes "$tmp_dir" "$flavor")
2045 ROOTFS_SIZE="$1 (estimated)"
2046 INITRAMFS_SIZE="$2 (estimated)"
2047 ISO_SIZE="$3 (estimated)"
2048 PKGNUM="$4"
2049 . "$storage/receipt"
2051 sed '/: $/d' > "$tmp_dir/$flavor.desc" <<EOT
2052 Flavor : $FLAVOR
2053 Description : $SHORT_DESC
2054 Version : $VERSION
2055 Maintainer : $MAINTAINER
2056 LiveCD RAM size : $FRUGAL_RAM
2057 Rootfs list : $ROOTFS_SELECTION
2058 Build date : $(date '+%Y%m%d at %T')
2059 Packages : $PKGNUM
2060 Rootfs size : $ROOTFS_SIZE
2061 Initramfs size : $INITRAMFS_SIZE
2062 ISO image size : $ISO_SIZE
2063 ================================================================================
2065 EOT
2067 rm -f $tmp_dir/packages.list
2068 pack_flavor "$tmp_dir" "$flavor"
2069 status
2070 display_unknown "$tmp_dir/err"
2071 display_warn "$flv_dir/warn"
2072 cleanup
2073 ;;
2076 get-flavor)
2077 # Get a flavor's files and prepare for gen-distro.
2078 flavor=${2%.flavor}
2079 title 'Preparing %s distro flavor' "$flavor"
2080 set -e
2081 [ -f "$flavor.flavor" ] || download "$flavor.flavor"
2082 set +e
2084 action 'Cleaning %s...' "$DISTRO"
2085 [ -d "$DISTRO" ] && rm -r "$DISTRO"
2086 # Clean old files
2087 for i in non-free.list distro-packages.list distro.sh receipt mirrors err; do
2088 [ -f "$i" ] && rm "$i"
2089 done
2090 mkdir -p "$DISTRO"
2091 status
2093 [ -z "$noup" ] && tazlito upgrade-flavor "$flavor.flavor"
2095 action 'Extracting flavor %s...' "$flavor.flavor"
2096 flv_dir="$(extract_flavor "$flavor" info)"
2097 cp -a "$flv_dir"/* .
2098 mv packages.list distro-packages.list
2099 mv -f info /etc/tazlito
2100 status
2102 for i in rootcd rootfs; do
2103 if [ -d "$i" ]; then
2104 mkdir -p "$ADDFILES"; mv "$i" "$ADDFILES/$i"
2105 fi
2106 done
2108 rm -f /etc/tazlito/rootfs.list
2109 grep -q '^Rootfs list' description &&
2110 grep '^Rootfs list' description | sed 's/.*: \(.*\)$/\1/' > /etc/tazlito/rootfs.list
2112 action 'Updating tazlito.conf...'
2113 [ -f tazlito.conf ] || cp /etc/tazlito/tazlito.conf .
2114 grep -v "^#VOLUM_NAME" < tazlito.conf | \
2115 sed "s/^VOLUM_NA/VOLUM_NAME=\"SliTaz $flavor\"\\n#VOLUM_NA/" \
2116 > tazlito.conf.$$ && mv tazlito.conf.$$ tazlito.conf
2117 sed -i "s/ISO_NAME=.*/ISO_NAME=\"slitaz-$flavor\"/" tazlito.conf
2118 status
2120 footer 'Flavor is ready to be generated by `tazlito gen-distro`'
2121 cleanup
2122 ;;
2125 iso2flavor)
2126 [ -z "$3" -o ! -s "$2" ] && die 'Usage: tazlito iso2flavor <image.iso> <flavor_name>' \
2127 '\n\nCreate a file <flavor_name>.flavor from the CD-ROM image file <image.iso>'
2129 FLAVOR=${3%.flavor}
2130 mkdir -p $TMP_DIR/iso $TMP_DIR/rootfs $TMP_DIR/flavor
2131 mount -o loop,ro $2 $TMP_DIR/iso
2132 flavordata $2 | (cd $TMP_DIR/flavor; cpio -i 2>/dev/null)
2133 if [ -s $TMP_DIR/iso/boot/rootfs1.gz -a \
2134 ! -s $TMP_DIR/flavor/*.desc ]; then
2135 echo "META flavors are not supported."
2136 umount -d $TMP_DIR/iso
2137 elif [ ! -s $TMP_DIR/iso/boot/rootfs.gz -a \
2138 ! -s $TMP_DIR/iso/boot/rootfs1.gz ]; then
2139 echo "No /boot/rootfs.gz in ISO image. Needs a SliTaz ISO."
2140 umount -d $TMP_DIR/iso
2141 else
2142 for i in $(ls -r $TMP_DIR/iso/boot/rootfs*gz); do
2143 ( zcat < $i || unlzma < $i ) | \
2144 ( cd $TMP_DIR/rootfs ; cpio -idmu > /dev/null 2>&1 )
2145 done
2146 if [ ! -s $TMP_DIR/rootfs/etc/slitaz-release ]; then
2147 echo "No file /etc/slitaz-release in /boot/rootfs.gz of iso image. Needs a non loram SliTaz iso."
2148 umount -d $TMP_DIR/iso
2149 else
2150 ROOTFS_SIZE=$(du -hs $TMP_DIR/rootfs | awk '{ print $1 }')
2151 RAM_SIZE=$(du -s $TMP_DIR/rootfs | awk '{ print 32*int(($1+36000)/32768) "M" }')
2152 cp -a $TMP_DIR/iso $TMP_DIR/rootcd
2153 ISO_SIZE=$(df -h $TMP_DIR/iso | awk 'END { print $2 }')
2154 BUILD_DATE=$(date '+%Y%m%d at %T' -r "$TMP_DIR/iso/md5sum")
2155 umount -d $TMP_DIR/iso
2156 INITRAMFS_SIZE=$(du -chs $TMP_DIR/rootcd/boot/rootfs*.gz | awk 'END { print $1 }')
2157 rm -f $TMP_DIR/rootcd/boot/rootfs.gz $TMP_DIR/rootcd/md5sum
2158 mv $TMP_DIR/rootcd/boot $TMP_DIR/rootfs
2159 sed 's/.* \(.*\).tazpkg*/\1/' > $TMP_DIR/$FLAVOR.pkglist \
2160 < $TMP_DIR/rootfs$INSTALLED.md5
2161 PKGCNT=$(grep -v ^# $TMP_DIR/$FLAVOR.pkglist | wc -l | awk '{ print $1 }')
2162 if [ -s $TMP_DIR/flavor/*desc ]; then
2163 cp $TMP_DIR/flavor/*.desc $TMP_DIR/$FLAVOR.desc
2164 [ -s $TMP_DIR/$FLAVOR.receipt ] &&
2165 cp $TMP_DIR/flavor/*.receipt $TMP_DIR/$FLAVOR.receipt
2166 for i in rootfs rootcd ; do
2167 [ -s $TMP_DIR/flavor/*.list$i ] &&
2168 sed 's/.\{1,45\}//;/^\.$/d' $TMP_DIR/flavor/*.list$i | \
2169 ( cd $TMP_DIR/$i ; cpio -o -H newc ) | gzip -9 > $TMP_DIR/$FLAVOR.$i
2170 done
2171 else
2172 find_flavor_rootfs $TMP_DIR/rootfs
2173 [ -d $TMP_DIR/rootfs/boot ] && mv $TMP_DIR/rootfs/boot $TMP_DIR/rootcd
2174 for i in rootfs rootcd ; do
2175 [ "$(ls $TMP_DIR/$i)" ] &&
2176 ( cd "$TMP_DIR/$i"; find * | cpio -o -H newc ) | gzip -9 > "$TMP_DIR/$FLAVOR.$i"
2177 done
2178 unset VERSION MAINTAINER
2179 echo -en "Flavor short description \007: "; read -t 30 DESCRIPTION
2180 if [ -n "$DESCRIPTION" ]; then
2181 echo -en "Flavor version : "; read -t 30 VERSION
2182 echo -en "Flavor maintainer (your email) : "; read -t 30 MAINTAINER
2183 fi
2185 cat > $TMP_DIR/$FLAVOR.desc <<EOT
2186 Flavor : $FLAVOR
2187 Description : ${DESCRIPTION:-SliTaz $FLAVOR flavor}
2188 Version : ${VERSION:-1.0}
2189 Maintainer : ${MAINTAINER:-nobody@slitaz.org}
2190 LiveCD RAM size : $RAM_SIZE
2191 Build date : $BUILD_DATE
2192 Packages : $PKGCNT
2193 Rootfs size : $ROOTFS_SIZE
2194 Initramfs size : $INITRAMFS_SIZE
2195 ISO image size : $ISO_SIZE
2196 ================================================================================
2198 EOT
2199 longline "Tazlito can't detect each file installed during \
2200 a package post_install. You should extract this flavor (tazlito extract-flavor \
2201 $FLAVOR), check the files in /home/slitaz/flavors/$(cat /etc/slitaz-release)/$FLAVOR/rootfs \
2202 tree and remove files generated by post_installs.
2203 Check /home/slitaz/flavors/$(cat /etc/slitaz-release)/$FLAVOR/receipt too and \
2204 repack the flavor (tazlito pack-flavor $FLAVOR)"
2205 fi
2206 ( cd $TMP_DIR; ls $FLAVOR.* | cpio -o -H newc ) | gzip -9 > $FLAVOR.flavor
2207 fi
2208 fi
2209 rm -rf $TMP_DIR
2210 ;;
2213 gen-distro)
2214 # Generate a live distro tree with a set of packages.
2216 check_root
2217 start_time=$(date +%s)
2219 # Tazlito options: --iso or --cdrom
2220 CDROM=''
2221 [ -n "$iso" ] && CDROM="-o loop $iso"
2222 [ -n "$cdrom" ] && CDROM="/dev/cdrom"
2224 # Check if a package list was specified on cmdline.
2225 if [ -f "$2" ]; then
2226 LIST_NAME="$2"
2227 else
2228 LIST_NAME='distro-packages.list'
2229 fi
2231 [ -d "$ROOTFS" -a -z "$forced" ] && die "A rootfs exists in '$DISTRO'." \
2232 'Please clean the distro tree or change directory path.'
2233 [ -d "$ROOTFS" ] && rm -rf "$ROOTFS"
2234 [ -d "$ROOTCD" ] && rm -rf "$ROOTCD"
2236 # If list not given: build list with all installed packages
2237 if [ ! -f "$LIST_NAME" -a -f "$LOCALSTATE/installed.info" ]; then
2238 awk -F$'\t' '{print $1}' "$LOCALSTATE/installed.info" >> "$LIST_NAME"
2239 fi
2241 # Exit if no list name.
2242 [ ! -f "$LIST_NAME" ] && die 'No packages list found or specified. Please read the docs.'
2244 # Start generation.
2245 title 'Tazlito generating a distro'
2247 # Misc checks
2248 mkdir -p "$PACKAGES_REPOSITORY"
2249 REPACK=$(yesorno 'Repack packages from rootfs?' 'n')
2251 # Mount CD-ROM to be able to repack boot-loader packages
2252 if [ ! -e /boot -a -n "$CDROM" ]; then
2253 mkdir $TMP_MNT
2254 if mount -r "$CDROM $TMP_MNT" 2>/dev/null; then
2255 ln -s "$TMP_MNT/boot" /
2256 if [ ! -d "$ADDFILES/rootcd" ] ; then
2257 mkdir -p "$ADDFILES/rootcd"
2258 for i in $(ls $TMP_MNT); do
2259 [ "$i" == 'boot' ] && continue
2260 cp -a "$TMP_MNT/$i" "$ADDFILES/rootcd"
2261 done
2262 fi
2263 else
2264 rmdir "$TMP_MNT"
2265 fi
2266 fi
2268 # Rootfs stuff.
2269 echo 'Preparing the rootfs directory...'
2270 mkdir -p "$ROOTFS"
2271 mkdir -p "$TMP_DIR"
2273 strip_versions "$LIST_NAME"
2275 if [ "$REPACK" == 'y' ]; then
2276 # Determine full packages list with all dependencies
2277 tmp_dir="$(mktemp -d)"
2278 cp "$LIST_NAME" "$tmp_dir/flavor.pkglist"
2279 touch "$tmp_dir/full.pkglist"
2280 calc_sizes "$tmp_dir" 'flavor' "$tmp_dir/full.pkglist" >/dev/null
2282 awk -F$'\t' '{printf "%s %s\n", $1, $2}' "$LOCALSTATE/installed.info" | \
2283 while read pkgname pkgver; do
2284 # Is package in full list?
2285 grep -q "^$pkgname$" "$tmp_dir/full.pkglist" || continue
2286 # Is package already repacked?
2287 [ -e "$PACKAGES_REPOSITORY/$pkgname-$pkgver.tazpkg" ] && continue
2288 _ 'Repacking %s...' "$pkgname-$pkgver"
2289 tazpkg repack "$pkgname" --quiet
2290 [ -f "$pkgname-$pkgver.tazpkg" ] && mv "$pkgname-$pkgver.tazpkg" "$PACKAGES_REPOSITORY"
2291 status
2292 done
2294 rm -r "$tmp_dir"
2295 fi
2297 # initial tazpkg setup in empty rootfs
2298 export root="$ROOTFS"
2299 tazpkg >/dev/null 2>&1
2300 # link rootfs packages cache to the regular packages cache
2301 rm -r "$ROOTFS/var/cache/tazpkg"
2302 ln -s /var/cache/tazpkg "$ROOTFS/var/cache/tazpkg"
2304 setup_mirrors mirrors
2306 # Just in case if flavor not contains "tazlito" package
2307 mkdir -p "$ROOTFS/etc/tazlito"
2309 if [ -f non-free.list ]; then
2310 # FIXME: working in the ROOTFS chroot?
2311 newline
2312 echo 'Preparing non-free packages...'
2313 cp 'non-free.list' "$ROOTFS/etc/tazlito/non-free.list"
2314 for pkg in $(cat 'non-free.list'); do
2315 if [ ! -d "$INSTALLED/$pkg" ]; then
2316 if [ ! -d "$INSTALLED/get-$pkg" ]; then
2317 tazpkg get-install get-$pkg
2318 fi
2319 get-$pkg "$ROOTFS"
2320 fi
2321 tazpkg repack $pkg
2322 pkg=$(ls $pkg*.tazpkg)
2323 grep -q "^$pkg$" $LIST_NAME || echo $pkg >> $LIST_NAME
2324 mv $pkg $PACKAGES_REPOSITORY
2325 done
2326 fi
2327 cp $LIST_NAME $DISTRO/distro-packages.list
2328 newline
2330 for pkg in $(cat $DISTRO/distro-packages.list); do
2331 action 'Installing package: %s' "$pkg"
2332 yes y | tazpkg -gi $pkg --root=$ROOTFS --quiet >> $log || exit 1
2333 status
2334 done
2335 newline
2337 restore_mirrors
2339 # Un-link packages cache
2340 rm $ROOTFS/var/cache/tazpkg
2341 # Clean /var/lib/tazpkg
2342 rm $ROOTFS/var/lib/tazpkg/ID* \
2343 $ROOTFS/var/lib/tazpkg/descriptions.txt \
2344 $ROOTFS/var/lib/tazpkg/extra.list \
2345 $ROOTFS/var/lib/tazpkg/files* \
2346 $ROOTFS/var/lib/tazpkg/packages* \
2347 $ROOTFS/var/lib/tazpkg/priority \
2348 -rf $ROOTFS/var/lib/tazpkg/undigest \
2349 2>/dev/null
2350 # Back to default mirror
2351 echo "$DEFAULT_MIRROR" > $ROOTFS/var/lib/tazpkg/mirror
2353 cd $DISTRO
2354 cp distro-packages.list $ROOTFS/etc/tazlito
2355 # Copy all files from $ADDFILES/rootfs to the rootfs.
2356 if [ -d "$ADDFILES/rootfs" ] ; then
2357 action 'Copying addfiles content to the rootfs...'
2358 cp -a $ADDFILES/rootfs/* $ROOTFS
2359 status
2360 fi
2362 action 'Root filesystem is generated...'; status
2364 # Root CD part.
2365 action 'Preparing the rootcd directory...'
2366 mkdir -p $ROOTCD
2367 status
2369 # Move the boot dir with the Linux kernel from rootfs.
2370 # The boot dir goes directly on the CD.
2371 if [ -d "$ROOTFS/boot" ] ; then
2372 action 'Moving the boot directory...'
2373 mv $ROOTFS/boot $ROOTCD
2374 cd $ROOTCD/boot
2375 make_bzImage_hardlink
2376 status
2377 fi
2378 cd $DISTRO
2379 # Copy all files from $ADDFILES/rootcd to the rootcd.
2380 if [ -d "$ADDFILES/rootcd" ] ; then
2381 action 'Copying addfiles content to the rootcd...'
2382 cp -a $ADDFILES/rootcd/* $ROOTCD
2383 status
2384 fi
2385 # Execute the distro script used to perform tasks in the rootfs
2386 # before compression. Give rootfs path in arg
2387 [ -z "$DISTRO_SCRIPT" ] && DISTRO_SCRIPT="$TOP_DIR/distro.sh"
2388 if [ -x "$DISTRO_SCRIPT" ]; then
2389 echo 'Executing distro script...'
2390 sh $DISTRO_SCRIPT $DISTRO
2391 fi
2393 # Execute the custom_rules() found in receipt.
2394 if [ -s "$TOP_DIR/receipt" ]; then
2395 if grep -q ^custom_rules "$TOP_DIR/receipt"; then
2396 echo -e "Executing: custom_rules()\n"
2397 . "$TOP_DIR/receipt"
2398 custom_rules || echo -e "\nERROR: custom_rules() failed\n"
2399 fi
2400 fi
2402 # Multi-rootfs
2403 if [ -s /etc/tazlito/rootfs.list ]; then
2405 FLAVOR_LIST="$(awk '{
2406 for (i = 2; i <= NF; i+=2)
2407 printf "%s ", i;
2408 }' /etc/tazlito/rootfs.list)"
2410 [ -s "$ROOTCD/boot/isolinux/isolinux.msg" ] &&
2411 sed -i "s/ *//;s/)/), flavors $FLAVOR_LIST/" \
2412 "$ROOTCD/boot/isolinux/isolinux.msg" 2>/dev/null
2414 [ -f "$ROOTCD/boot/isolinux/ifmem.c32" -o \
2415 -f "$ROOTCD/boot/isolinux/c32box.c32" ] ||
2416 cp '/boot/isolinux/c32box.c32' "$ROOTCD/boot/isolinux" 2>/dev/null ||
2417 cp '/boot/isolinux/ifmem.c32' "$ROOTCD/boot/isolinux"
2419 n=0
2420 last=$ROOTFS
2421 while read flavor; do
2422 n=$(($n+1))
2423 newline
2424 boldify "Building $flavor rootfs..."
2426 [ -s "$TOP_DIR/$flavor.flavor" ] &&
2427 cp "$TOP_DIR/$flavor.flavor" .
2429 if [ ! -s "$flavor.flavor" ]; then
2430 # We may have it in $FLAVORS_REPOSITORY
2431 if [ -d "$FLAVORS_REPOSITORY/$flavor" ]; then
2432 tazlito pack-flavor $flavor
2433 else
2434 download $flavor.flavor
2435 fi
2436 fi
2438 action 'Extracting %s and %s...' "$flavor.pkglist" "$flavor.rootfs"
2439 zcat $flavor.flavor | cpio -i --quiet $flavor.pkglist $flavor.rootfs
2440 sed 's/.*/&.tazpkg/' < $flavor.pkglist > $DISTRO/list-packages0$n
2441 status
2443 strip_versions "$DISTRO/list-packages0$n"
2445 mkdir ${ROOTFS}0$n
2446 # Install packages
2447 cd $PACKAGES_REPOSITORY
2449 # initial tazpkg setup in empty rootfs
2450 export root="${ROOTFS}0$n"
2451 tazpkg >/dev/null 2>&1
2452 # link rootfs packages cache to the regular packages cache
2453 rm -r "${ROOTFS}0$n/var/cache/tazpkg"
2454 ln -s /var/cache/tazpkg "${ROOTFS}0$n/var/cache/tazpkg"
2456 setup_mirrors mirrors
2458 # Just in case if flavor not contains "tazlito" package
2459 mkdir -p "${ROOTFS}0$n/etc/tazlito"
2462 for pkg in $(cat $DISTRO/list-packages0$n); do
2463 action 'Installing package: %s' "$pkg"
2464 yes y | tazpkg -gi $pkg --root=${ROOTFS}0$n --quiet >> $log || exit 1
2465 status
2466 done
2468 restore_mirrors
2470 rm -rf ${ROOTFS}0$n/boot
2472 # Un-link packages cache
2473 rm ${ROOTFS}0$n/var/cache/tazpkg
2475 # Clean /var/lib/tazpkg
2476 rm ${ROOTFS}0$n/var/lib/tazpkg/ID* \
2477 ${ROOTFS}0$n/var/lib/tazpkg/descriptions.txt \
2478 ${ROOTFS}0$n/var/lib/tazpkg/extra.list \
2479 ${ROOTFS}0$n/var/lib/tazpkg/files* \
2480 ${ROOTFS}0$n/var/lib/tazpkg/packages.* \
2481 ${ROOTFS}0$n/var/lib/tazpkg/priority \
2482 -rf ${ROOTFS}0$n/var/lib/tazpkg/undigest \
2483 2>/dev/null
2485 # Back to default mirror
2486 echo "$DEFAULT_MIRROR" > ${ROOTFS}0$n/var/lib/tazpkg/mirror
2489 cd $DISTRO
2490 if [ -s $flavor.rootfs ]; then
2491 echo -n "Adding $flavor rootfs extra files..."
2492 zcat < $flavor.rootfs | ( cd ${ROOTFS}0$n ; cpio -idmu )
2493 fi
2495 action 'Moving %s to %s' "list-packages0$n" "rootfs0$n"
2496 mv $DISTRO/list-packages0$n ${ROOTFS}0$n/etc/tazlito/distro-packages.list
2497 status
2499 rm -f $flavor.flavor install-list
2500 mergefs ${ROOTFS}0$n $last
2501 last=${ROOTFS}0$n
2502 done <<EOT
2503 $(awk '{ for (i = 4; i <= NF; i+=2) print $i; }' < /etc/tazlito/rootfs.list)
2504 EOT
2505 #'
2506 i=$(($n+1))
2507 while [ $n -gt 0 ]; do
2508 mv ${ROOTFS}0$n ${ROOTFS}$i
2509 echo "Compressing ${ROOTFS}0$n ($(du -hs ${ROOTFS}$i | awk '{ print $1 }'))..."
2510 gen_initramfs ${ROOTFS}$i
2511 n=$(($n-1))
2512 i=$(($i-1))
2513 done
2514 mv $ROOTFS ${ROOTFS}$i
2515 gen_initramfs ${ROOTFS}$i
2516 update_bootconfig $ROOTCD/boot/isolinux \
2517 "$(cat /etc/tazlito/rootfs.list)"
2518 else
2519 # Initramfs and ISO image stuff.
2520 gen_initramfs $ROOTFS
2521 fi
2522 gen_livecd_isolinux
2523 distro_stats
2524 cleanup
2525 ;;
2528 clean-distro)
2529 # Remove old distro tree.
2531 check_root
2532 title 'Cleaning: %s' "$DISTRO"
2533 if [ -d "$DISTRO" ] ; then
2534 if [ -d "$ROOTFS" ] ; then
2535 action 'Removing the rootfs...'
2536 rm -f $DISTRO/$INITRAMFS
2537 rm -rf $ROOTFS
2538 status
2539 fi
2540 if [ -d "$ROOTCD" ] ; then
2541 action 'Removing the rootcd...'
2542 rm -rf $ROOTCD
2543 status
2544 fi
2545 action 'Removing eventual ISO image...'
2546 rm -f $DISTRO/$ISO_NAME.iso
2547 rm -f $DISTRO/$ISO_NAME.md5
2548 status
2549 fi
2550 footer
2551 ;;
2554 check-distro)
2555 # Check for a few LiveCD needed files not installed by packages.
2557 # TODO: Remove this function.
2558 # First two files are maintained by tazpkg while it runs on rootfs,
2559 # while last one file should be maintained by tazlito itself.
2560 check_rootfs
2561 title 'Checking distro: %s' "$ROOTFS"
2562 # SliTaz release info.
2563 if [ ! -f "$ROOTFS/etc/slitaz-release" ]; then
2564 echo "Missing release info : /etc/slitaz-release"
2565 else
2566 release=$(cat $ROOTFS/etc/slitaz-release)
2567 echo -n "Release : $release"
2568 status
2569 fi
2570 # Tazpkg mirror.
2571 if [ ! -f "$ROOTFS$LOCALSTATE/mirror" ]; then
2572 echo -n "Mirror URL : Missing $LOCALSTATE/mirror"
2573 todomsg
2574 else
2575 action 'Mirror configuration exists...'
2576 status
2577 fi
2578 # Isolinux msg
2579 if grep -q "cooking-XXXXXXXX" /$ROOTCD/boot/isolinux/isolinux.*g; then
2580 echo -n "Isolinux msg : Missing cooking date XXXXXXXX (ex $(date +%Y%m%d))"
2581 todomsg
2582 else
2583 action 'Isolinux message seems good...'
2584 status
2585 fi
2586 footer
2587 ;;
2590 writeiso)
2591 # Writefs to ISO image including /home unlike gen-distro we don't use
2592 # packages to generate a rootfs, we build a compressed rootfs with all
2593 # the current filesystem similar to 'tazusb writefs'.
2595 DISTRO='/home/slitaz/distro'
2596 ROOTCD="$DISTRO/rootcd"
2597 COMPRESSION="${2:-none}"
2598 ISO_NAME="${3:-slitaz}"
2599 check_root
2600 # Start info
2601 title 'Write filesystem to ISO'
2602 longline "The command writeiso will write the current filesystem into a \
2603 suitable cpio archive (rootfs.gz) and generate a bootable ISO image (slitaz.iso)."
2604 newline
2605 emsg "<b>Archive compression:</b> <c 36>$COMPRESSION</c>"
2607 [ "$COMPRESSION" == 'gzip' ] && colorize 31 "gzip-compressed rootfs unsupported and may fail to boot"
2608 # Save some space
2609 rm -rf /var/cache/tazpkg/*
2610 rm -f /var/lib/tazpkg/*.bak
2611 rm -rf $DISTRO
2613 # Optionally remove sound card selection and screen resolution.
2614 if [ -z $LaunchedByTazpanel ]; then
2615 echo "Do you wish to remove the sound card and screen configs ? "
2616 echo -n "Press ENTER to keep or answer (No|yes|exit): "
2617 read anser
2618 case $anser in
2619 e|E|"exit"|Exit)
2620 exit 0 ;;
2621 y|Y|yes|Yes)
2622 echo -n "Removing current sound card and screen configurations..."
2623 rm -f /var/lib/sound-card-driver
2624 rm -f /var/lib/alsa/asound.state
2625 rm -f /etc/X11/xorg.conf ;;
2626 *)
2627 echo -n "Keeping current sound card and screen configurations..." ;;
2628 esac
2629 status
2630 newline
2632 # Optionally remove i18n settings
2633 echo "Do you wish to remove local/keymap settings ? "
2634 echo -n "Press ENTER to keep or answer (No|yes|exit): "
2635 read anser
2636 case $anser in
2637 e|E|"exit"|Exit)
2638 exit 0 ;;
2639 y|Y|yes|Yes)
2640 echo "Removing current locale/keymap settings..."
2641 newline > /etc/locale.conf
2642 newline > /etc/keymap.conf ;;
2643 *)
2644 echo "Keeping current locale/keymap settings..." ;;
2645 esac
2646 status
2647 fi
2649 # Clean-up files by default
2650 newline > /etc/udev/rules.d/70-persistent-net.rules
2651 newline > /etc/udev/rules.d/70-persistant-cd.rules
2653 # Create list of files including default user files since it is defined in /etc/passwd
2654 # and some new users might have been added.
2655 cd /
2656 echo 'init' > /tmp/list
2657 for dir in bin etc sbin var dev lib root usr home opt; do
2658 [ -d $dir ] && find $dir
2659 done >> /tmp/list
2661 for dir in proc sys tmp mnt media media/cdrom media/flash media/usbdisk run run/udev; do
2662 [ -d $dir ] && echo $dir
2663 done >> /tmp/list
2665 sed '/var\/run\/.*pid$/d ; /var\/run\/utmp/d ; /.*\/.gvfs/d ; /home\/.*\/.cache\/.*/d' -i /tmp/list
2667 #if [ ! $(find /var/log/slitaz/tazpkg.log -size +4k) = "" ]; then
2668 # sed -i "/var\/log\/slitaz\/tazpkg.log/d" /tmp/list
2669 #fi
2670 mv -f /var/log/wtmp /tmp/tazlito-wtmp
2671 touch /var/log/wtmp
2673 for removelog in auth boot messages dmesg daemon slim .*old Xorg tazpanel cups; do
2674 sed -i "/var\/log\/$removelog/d" /tmp/list
2675 done
2677 # Generate initramfs with specified compression and display rootfs
2678 # size in realtime.
2679 rm -f /tmp/.write-iso* /tmp/rootfs 2>/dev/null
2681 write_initramfs &
2682 sleep 2
2683 cd - > /dev/null
2684 echo -en "\nFilesystem size:"
2685 while [ ! -f /tmp/rootfs ]; do
2686 sleep 1
2687 echo -en "\\033[18G$(du -sh /$INITRAMFS | awk '{print $1}') "
2688 done
2689 mv -f /tmp/tazlito-wtmp /var/log/wtmp
2690 echo -e "\n"
2691 rm -f /tmp/rootfs
2693 # Move freshly generated rootfs to the cdrom.
2694 mkdir -p $ROOTCD/boot
2695 mv -f /$INITRAMFS $ROOTCD/boot
2696 echo "Located in: $ROOTCD/boot/$INITRAMFS"
2698 # Now we need the kernel and isolinux files.
2699 copy_from_cd() {
2700 cp /media/cdrom/boot/bzImage* $ROOTCD/boot
2701 cp -a /media/cdrom/boot/isolinux $ROOTCD/boot
2702 unmeta_boot $ROOTCD
2703 umount /media/cdrom
2706 bootloader='/var/lib/tazpkg/installed/syslinux/volatile.cpio.gz'
2707 if mount /dev/cdrom /media/cdrom 2>/dev/null; then
2708 copy_from_cd;
2709 elif mount | grep /media/cdrom; then
2710 copy_from_cd;
2711 elif [ -f "$bootloader" -a -f /boot/vmlinuz*slitaz* ]; then
2712 cp $bootloader $ROOTCD
2713 cd $ROOTCD
2714 zcat volatile.cpio.gz | cpio -id
2715 rm -f volatile.cpio.gz
2716 [ -f /boot/*slitaz ] && \
2717 cp /boot/vmlinuz*slitaz $ROOTCD/boot/bzImage
2718 [ -f /boot/*slitaz64 ] && \
2719 cp /boot/vmlinuz*slitaz64 $ROOTCD/boot/bzImage64
2720 else
2721 touch /tmp/.write-iso-error
2722 longline "When SliTaz is running in RAM the kernel and bootloader \
2723 files are kept on the CD-ROM. Please insert a Live CD or loop mount the \
2724 slitaz.iso to /media/cdrom (run # mount -o loop slitaz-rolling.iso /media/cdrom ) \
2725 or # (tazpkg -gi linux --forced) to let Tazlito copy the files."
2726 echo -en "----\nENTER to continue..."; read i
2727 [ ! -d /media/cdrom/boot/isolinux ] && exit 1
2728 copy_from_cd
2729 fi
2731 # Generate the iso image.
2732 touch /tmp/.write-iso
2733 newline
2734 cd $DISTRO
2735 echo "Generating ISO image..."
2736 genisoimage -R -o $ISO_NAME.iso -b boot/isolinux/isolinux.bin \
2737 -c boot/isolinux/boot.cat -no-emul-boot -boot-load-size 4 \
2738 -V "SliTaz" -p "$(id -un)" -input-charset utf-8 \
2739 -P "$(hostname)" -boot-info-table $ROOTCD
2740 if [ -x /usr/bin/isohybrid ]; then
2741 action 'Creating hybrid ISO/disk...'
2742 /usr/bin/isohybrid $ISO_NAME.iso -entry 2 2>/dev/null
2743 status
2744 fi
2745 if [ -x /usr/bin/iso2exe ]; then
2746 action 'Creating hybrid ISO/EXE...'
2747 /usr/bin/iso2exe $ISO_NAME.iso 2>/dev/null
2748 status
2749 fi
2750 action 'Creating the ISO md5sum...'
2751 md5sum $ISO_NAME.iso > $ISO_NAME.md5
2752 status
2754 separator
2755 echo "ISO image: $(du -sh $DISTRO/$ISO_NAME.iso)"
2756 rm -f /tmp/.write-iso
2757 newline
2758 if [ -z $LaunchedByTazpanel ]; then
2759 echo -n "Exit or burn ISO to CD-ROM (Exit|burn)? "; read anser
2760 case $anser in
2761 burn)
2762 umount /dev/cdrom 2>/dev/null
2763 eject
2764 echo -n "Please insert a blank CD-ROM and press ENTER..."
2765 read i && sleep 2
2766 tazlito burn-iso $DISTRO/$ISO_NAME.iso
2767 echo -en "----\nENTER to continue..."; read i ;;
2768 *)
2769 exit 0 ;;
2770 esac
2771 fi
2772 ;;
2775 burn-iso)
2776 # Guess CD-ROM device, ask user and burn the ISO.
2778 check_root
2779 DRIVE_NAME=$(grep "drive name" /proc/sys/dev/cdrom/info | cut -f3)
2780 DRIVE_SPEED=$(grep "drive speed" /proc/sys/dev/cdrom/info | cut -f3)
2781 # We can specify an alternative ISO from the cmdline.
2782 iso="${2:-$DISTRO/$ISO_NAME.iso}"
2783 [ ! -f "$iso" ] && die "Unable to find ISO: $iso"
2785 title 'Tazlito burn ISO'
2786 echo "CD-ROM device : /dev/$DRIVE_NAME"
2787 echo "Drive speed : $DRIVE_SPEED"
2788 echo "ISO image : $iso"
2789 footer
2791 case $(yesorno 'Burn ISO image?' 'n') in
2792 y)
2793 title 'Starting Wodim to burn the ISO...'
2794 sleep 2
2795 wodim speed=$DRIVE_SPEED dev=/dev/$DRIVE_NAME $iso
2796 footer 'ISO image is burned to CD-ROM.'
2797 ;;
2798 *)
2799 die 'Exiting. No ISO burned.'
2800 ;;
2801 esac
2802 ;;
2805 merge)
2806 # Merge multiple rootfs into one iso.
2808 if [ -z "$2" ]; then
2809 cat <<EOT
2810 Usage: tazlito merge size1 iso size2 rootfs2 [sizeN rootfsN]...
2812 Merge multiple rootfs into one ISO. Rootfs are like russian dolls
2813 i.e: rootfsN is a subset of rootfsN-1
2814 rootfs1 is found in ISO, sizeN is the RAM size needed to launch rootfsN.
2815 The boot loader will select the rootfs according to the RAM size detected.
2817 Example:
2818 $ tazlito merge 160M slitaz-core.iso 96M rootfs-justx.gz 32M rootfs-base.gz
2820 Will start slitaz-core with 160M+ RAM, slitaz-justX with 96M-160M RAM,
2821 slitaz-base with 32M-96M RAM and display an error message if RAM < 32M.
2823 EOT
2824 exit 2
2825 fi
2827 shift # skip merge
2828 append="$1 slitaz1"
2829 shift # skip size1
2830 mkdir -p $TMP_DIR/mnt $TMP_DIR/rootfs1
2832 ISO=$1.merged
2834 # Extract filesystems
2835 action 'Mounting %s' "$1"
2836 mount -o loop,ro $1 $TMP_DIR/mnt 2> /dev/null
2837 status || cleanup_merge
2839 cp -a $TMP_DIR/mnt $TMP_DIR/iso
2840 make_bzImage_hardlink $TMP_DIR/iso/boot
2841 umount -d $TMP_DIR/mnt
2842 if [ -f $TMP_DIR/iso/boot/rootfs1.gz ]; then
2843 echo "$1 is already a merged iso. Aborting."
2844 cleanup_merge
2845 fi
2846 if [ ! -f $TMP_DIR/iso/boot/isolinux/ifmem.c32 -a
2847 ! -f $TMP_DIR/iso/boot/isolinux/c32box.c32 ]; then
2848 if [ ! -f /boot/isolinux/ifmem.c32 -a
2849 ! -f /boot/isolinux/c32box.c32 ]; then
2850 cat <<EOT
2851 No file /boot/isolinux/ifmem.c32
2852 Please install syslinux package !
2853 EOT
2854 rm -rf $TMP_DIR
2855 exit 1
2856 fi
2857 cp /boot/isolinux/c32box.c32 $TMP_DIR/iso/boot/isolinux 2> /dev/null ||
2858 cp /boot/isolinux/ifmem.c32 $TMP_DIR/iso/boot/isolinux
2859 fi
2861 action 'Extracting iso/rootfs.gz'
2862 extract_rootfs $TMP_DIR/iso/boot/rootfs.gz $TMP_DIR/rootfs1 &&
2863 [ -d $TMP_DIR/rootfs1/etc ]
2864 status || cleanup_merge
2866 n=1
2867 while [ -n "$2" ]; do
2868 shift # skip rootfs N-1
2869 p=$n
2870 n=$(($n + 1))
2871 append="$append $1 slitaz$n"
2872 shift # skip size N
2873 mkdir -p $TMP_DIR/rootfs$n
2875 action 'Extracting %s' "$1"
2876 extract_rootfs $1 $TMP_DIR/rootfs$n &&
2877 [ -d "$TMP_DIR/rootfs$n/etc" ]
2878 status || cleanup_merge
2880 mergefs $TMP_DIR/rootfs$n $TMP_DIR/rootfs$p
2881 action 'Creating rootfs%s.gz' "$p"
2882 pack_rootfs "$TMP_DIR/rootfs$p" "$TMP_DIR/iso/boot/rootfs$p.gz"
2883 status
2884 done
2885 action 'Creating rootfs%s.gz' "$n"
2886 pack_rootfs "$TMP_DIR/rootfs$n" "$TMP_DIR/iso/boot/rootfs$n.gz"
2887 status
2888 rm -f $TMP_DIR/iso/boot/rootfs.gz
2889 update_bootconfig $TMP_DIR/iso/boot/isolinux "$append"
2890 create_iso $ISO $TMP_DIR/iso
2891 rm -rf $TMP_DIR
2892 ;;
2895 repack)
2896 # Repack an iso with maximum lzma compression ratio.
2898 ISO=$2
2899 mkdir -p $TMP_DIR/mnt
2901 # Extract filesystems
2902 action 'Mounting %s' "$ISO"
2903 mount -o loop,ro $ISO $TMP_DIR/mnt 2>/dev/null
2904 status || cleanup_merge
2906 cp -a $TMP_DIR/mnt $TMP_DIR/iso
2907 umount -d $TMP_DIR/mnt
2909 for i in $TMP_DIR/iso/boot/rootfs* ; do
2910 action 'Repacking %s' "$(basename $i)"
2911 (zcat $i 2>/dev/null || unlzma < $i || cat $i) 2>/dev/null > $TMP_DIR/rootfs
2912 lzma e $TMP_DIR/rootfs $i $(lzma_switches $TMP_DIR/rootfs)
2913 align_to_32bits $i
2914 status
2915 done
2917 create_iso $ISO $TMP_DIR/iso
2918 rm -rf $TMP_DIR
2919 ;;
2922 build-loram)
2923 # Build a Live CD for low RAM systems.
2925 ISO="$2"
2926 OUTPUT="$3"
2927 [ -z "$3" ] && \
2928 die "Usage: tazlito build-loram <input>.iso <output>.iso [cdrom|smallcdrom|http|ram]"
2929 mkdir -p "$TMP_DIR/iso"
2930 mount -o loop,ro -t iso9660 "$ISO" "$TMP_DIR/iso"
2931 loopdev=$( (losetup -a 2>/dev/null || losetup) | sed "/$ISO$/!d;s/:.*//;q")
2932 if ! check_iso_for_loram ; then
2933 umount -d "$TMP_DIR/iso"
2934 die "$ISO is not a valid SliTaz live CD. Abort."
2935 fi
2936 case "$4" in
2937 cdrom) build_loram_cdrom ;;
2938 http) build_loram_http ;;
2939 *) build_loram_ram ;;
2940 esac
2941 umount $TMP_DIR/iso # no -d: needs /proc
2942 losetup -d $loopdev
2943 rm -rf $TMP_DIR
2944 ;;
2947 emu-iso)
2948 # Emulate an ISO image with Qemu.
2949 iso="${2:-$DISTRO/$ISO_NAME.iso}"
2950 [ -f "$iso" ] || die "Unable to find ISO file '$iso'."
2951 [ -x '/usr/bin/qemu' ] || die "Unable to find Qemu binary. Please install package 'qemu'."
2952 echo -e "\nStarting Qemu emulator:\n"
2953 echo -e "qemu $QEMU_OPTS $iso\n"
2954 qemu $QEMU_OPTS $iso
2955 ;;
2958 deduplicate)
2959 # Deduplicate files in a tree
2960 shift
2961 deduplicate "$@"
2962 ;;
2965 usage|*)
2966 # Print usage also for all unknown commands.
2967 usage
2968 ;;
2969 esac
2971 exit 0