#!/bin/bash # # makesd # partition and format an SD card suitable for GTA04 devices (Letux 2804 etc.) # run this script on some host with a SD interface # (c) Golden Delicious Comp. GmbH&Co. KG, 2014-2018 # Licenced under GPLv2 # DEBUG=false DRYRUN=false [ "$BOOT_VARIANT" ] || BOOT_VARIANT=stable [ "$KERNEL_VARIANT" ] || KERNEL_VARIANT=stable [ "$ROOTFS_VARIANT" ] || ROOTFS_VARIANT=stable [ "$ARCHITECTURE" ] || ARCHITECTURE=-armhf [ "$DEV" ] || DEV="$(cat ~/.makesd.conf 2>/dev/null)" [ "$DEV" ] || DEV=/dev/null # no default set! CMDLINE="DEV=$DEV $0 $@" # save how makesd was called function macros() { # format: macro-pattern macro-body # it is valid to use shell variables in the body since they are expanded by the here-document # $1 is expanded by the first argument given to the macros() call # patterns are regexp (expr : command) # comments (lines starting with "#" can be used and they are ignored # macros can be recursive cat </dev/null then # found $DEBUG && echo "$1" matches "$MACRO -> $COMMAND" >&2 echo "$COMMAND" return fi esac done $DEBUG && echo "$1" no match >&2 echo "" } } function useage() { ## fixme: list available macros separately cat < raw copy of remote file into directory file -x[dir] raw expand of remote package into directory dir (trying different suffixes like .tar, .tbz) [can be specified multiple times] -dd copy binary file to current position (as defined by -p) [can be specified multiple times] -I write makesd.info to current partition - should be used if there is no -b bootloader: -b[dir] -b[dir] version -b none device tree files: -d[dir] -d[dir] version -d none kernel: -k[dir] -k[dir] version -k none modules: -m version -m none config patches: -c -c none root file system (OS): -r -r none -r debian -r lxde -r quantumstep -r replicant -r qtmoko -r pyraos -v variant -- choose different variant for -r and many macros (default is 'stable') -vb variant -- different variant for boot -vk variant -- different variant for kernel, device tree and modules -vr variant -- different variant for rootfs -A architecture -- choose different architecture variant macros for single partition cards: lxde = -f ext4 -r lxde -d all -k \$VARIANT -m \$VARIANT -c \$VARIANT qtmoko = -f ext4 -r qtmoko -d all -k \$VARIANT (does not need config) replicant = -f ext4 -d all -r replicant-4.2 (has its own kernel) quantumstep = -f ext4 -r quantumstep -d all -k \$VARIANT -m \$VARIANT -c \$VARIANT macros for multiple partitions (to create bootable production image SD card): gta04 | l2804 = -f fat -b \$VARIANT lxde gta04one | gta04a5 = -f fat -b \$VARIANT/GTA04A5 lxde gta04b2 | l3704 = -f fat -b \$VARIANT/b2 lxde gta04b3 | l7004 = -f fat -b \$VARIANT/b3 lxde gta04b7 | neo900 = -f fat -b \$VARIANT/b7 lxde bb = -f fat -b \$VARIANT/ beagleboard lxde bbb = -f fat -b \$VARIANT/ beagleboardblack lxde panda-es = -f fat -b \$VARIANT/panda-es lxde pyraos = -f fat -b \$VARIANT/ pyra pyraos openpandora = -f fat -b \$VARIANT/ openpandora lxde all = lxde qtmoko replicant quantumstep examples:" makesd -- makes a single-partition LXDE image makesd lxde -- also makes a LXDE image makesd replicant -- makes a single partition replicant image makesd all -- makes a 4-partition card makesd gta04 -- makes the stable production (recovery) image for the GTA04 (includes boot loader) makesd gta04 -f1 -b GTA04/2015-10-25 -- makes the \$VARIANT image for the GTA04 but use U-Boot from 2015-10-25 makesd gta04 -d letux-4.10.4 -k letux-4.10.4 -m letux-4.10.4 -- replace DT, kernel and modules by specific version makesd pyra -r https://download.goldelico.com/letux-debian-rootfs/stable-pyraos.tbz -- install stable PyraOS makesd -v latest gta04 -- makes an unstable production image makesd -v latest gta04 -f1 quantumstep -- makes an unstable production image but with quantumstep rootfs makesd -v 20141006-GTA04-beta-3.17.0-wheezy-7.6 l3704 -- makes the specified version for the Letux 3704 makesd -vk letux-5.12.1 -f1 quantumstep -- makes a production image with specific kernel but with quantumstep rootfs DEV=/dev/sdd makesd --dry -- does a dry run on /dev/sdd makesd -u -- self-update DEV=/dev/sdd makesd omap5432evm -f1 -b OMAP5432-uEVM/2016-05-10 -k letux-4.8-rc6 -d letux-4.8-rc6 -f2 -m letux-4.8-rc6 xfce DEV=/dev/sdb makesd pyra -f1 -k letux-4.11-rc4 -d letux-4.11-rc4 -v 20170401-jessie-8.7 lxde -m letux-4.11-rc4 END } function setparam() { # $partition $name $value if [ "(" "$1" -lt 1 -o "$1" -gt 4 ")" ] then echo "invalid partition number $1" >&2 useage exit 1 fi $DEBUG && echo setparam $1 $2 $3 eval $2$1="'$3'" } function getparam() { # $partition $name eval echo \"\$$2$1\" } DDLIST="" XLIST="" function process() { # $1 .. $n echo "$@" >>.makesd.log while [ "$1" ] do $DEBUG && echo "command $1" >&2 case "$1" in -f[0-4] ) # switch to given partition NP=$(expr "$1" : "-f\([0-4]\).*" ) $DEBUG && echo "switched to partition $NP" >&2 ;; -f- ) # switch to previous partition NP=$(expr "$NP" - 1) if [ "$NP" -lt 0 ] then echo "can't go back that far" >&2 useage exit 1 fi ;; -f ) # switch to next partition and define format NP=$(expr "$NP" + 1) if [ "$NP" -gt 4 ] then echo "too many partitions specified (max. 4)" >&2 useage exit 1 fi shift case "$1" in none ) : skip ;; fat* ) setparam $NP NAME "boot$FATNUM" # define default FATNUM=$(expr "${FATNUM:=1}" + 1) # first has no suffix, second gets suffix "2" ;; ext* ) # FIXME: scan all partitions for first "free" name in namespace... # so that -n can overwrite a name which does not count here setparam $NP NAME "rootfs$EXTNUM" # define default EXTNUM=$(expr "${EXTNUM:=1}" + 1) # first has no suffix, second gets suffix "2" ;; swap ) setparam $NP NAME "swap$SWAPNUM" # define default SWAPNUM=$(expr "${SWAPNUM:=1}" + 1) # first has no suffix, second gets suffix "2" ;; * ) echo "unknown partition type $1" >&2 useage exit 1 ;; esac setparam $NP FORMAT "$1" setparam $NP SIZE "25" setparam $NP PSTART "$PSTART" PSTART="" if [ "$1" = "none" ] then # don't install anything setparam $NP BOOT "none" setparam $NP KERNEL "none" setparam $NP MODULES "none" setparam $NP DT "none" setparam $NP ROOTFS "none" setparam $NP CONFIG "none" fi ;; -s ) # define relative size (typically in %) # FIXME: there should be a mechanism to define minimum or maximum size in kMG Bytes shift setparam $NP SIZE "$1" ;; -n ) # define partition name shift setparam $NP NAME "$1" ;; -F ) # define partition type shift case "$1" in fat* | ext* | swap ) setparam $NP FORMAT "$1" $DEBUG && echo "switched partition $NP to $1" >&2 ;; * ) echo "unknown partition type $1" >&2 useage exit 1 ;; esac ;; -p ) # define partition or dd start sector (must come before -f or -p) shift PSTART="$1" ;; -I* ) # write info # should we allow a subdirectory? setparam $NP INFO "true" ;; -dd ) # copy (raw) file to current partition start shift if ! [ "$PSTART" ] then echo "missing partition start (-p sector)" >&2 useage exit 1 fi case "$1" in http://* | https://* | file:* ) local F="$1" ;; * ) # relative to boot directory local F=$(lookup "-B$1") ;; esac if [ "$DDLIST" ] then DDLIST="$DDLIST $PSTART $F" # append new line else DDLIST="$PSTART $F" # first line fi ;; -x* ) # low level extract of url file/package into given directory/file local SUBDIR=${1:2} [ "$SUBDIR" ] || SUBDIR=/ SUBDIR=$(echo "$SUBDIR" | sed 's|\.\./||g') # protect - not perfect - .../file -> .file shift local XLIST="$(getparam $NP XLIST)" if [ "$XLIST" ] then XLIST="$XLIST $SUBDIR $1" # append new line else XLIST="$SUBDIR $1" # first line fi setparam $NP XLIST "$XLIST" ;; -b* ) # define boot loader setparam $NP BOOTDIR "$(expr "$1" : "-b\(.*\)")" shift $DEBUG && echo "bootloader $1" >&2 local P=$(lookup "-b$1") if [ ! "$P" ] then echo "unknown macro: -k $1" >&2; useage >&2; exit 1 fi setparam $NP BOOT "$P" ;; -k* ) # define kernel setparam $NP KERNELDIR "$(expr "$1" : "-k\(.*\)")" shift $DEBUG && echo "kernel $1" >&2 local P=$(lookup "-k$1") if [ ! "$P" ] then echo "unknown macro: -k $1" >&2; useage >&2; exit 1 fi setparam $NP KERNEL "$P" ;; -m ) # define modules shift $DEBUG && echo "modules $1" >&2 local P=$(lookup "-m$1") if [ ! "$P" ] then echo "unknown macro: -k $1" >&2; useage >&2; exit 1 fi setparam $NP MODULES "$P" ;; -d* ) # define device trees setparam $NP DTDIR "$(expr "$1" : "-d\(.*\)")" shift $DEBUG && echo "device trees $1" >&2 local P=$(lookup "-d$1") if [ ! "$P" ] then echo "unknown macro: -k $1" >&2; useage >&2; exit 1 fi setparam $NP DT "$P" ;; -r ) # define root file system shift $DEBUG && echo "rootfs $1" >&2 local P=$(lookup "-r$1") if [ ! "$P" ] then echo "unknown macro: -k $1" >&2; useage >&2; exit 1 fi setparam $NP ROOTFS "$P" ;; -c ) # define additional config shift $DEBUG && echo "config $1" >&2 local P=$(lookup "-c$1") if [ ! "$P" ] then echo "unknown macro: -k $1" >&2; useage >&2; exit 1 fi setparam $NP CONFIG "$P" ;; -v ) # define variant shift $DEBUG && echo "variant $1" >&2 [ "$1" ] && BOOT_VARIANT="$1" KERNEL_VARIANT="$1" ROOTFS_VARIANT="$1" # overwrite ;; -vb ) # define boot variant shift $DEBUG && echo "boot variant $1" >&2 [ "$1" ] && BOOT_VARIANT="$1" # overwrite ;; -vk ) # define kernel variant shift $DEBUG && echo "kernel variant $1" >&2 [ "$1" ] && KERNEL_VARIANT="$1" # overwrite ;; -vr ) # define rootfs variant shift $DEBUG && echo "rootfs variant $1" >&2 [ "$1" ] && ROOTFS_VARIANT="$1" # overwrite ;; -A ) # define architecture shift $DEBUG && echo "architecture $1" >&2 [ "$1" ] && ARCHITECTURE="-$1" # overwrite with hyphen prefix ;; -* ) echo "unknown option: $1" >&2; useage >&2; exit 1 ;; * ) local COMMAND=$(lookup "$1") if [ "$COMMAND" ] then process $COMMAND else echo "unknown macro: $1" >&2; useage >&2; exit 1 fi ;; esac shift done } function tool() { # check if tool exists which "$1" >/dev/null } function exists() { # check if $url can be downloaded $DEBUG && echo "-- exists $1 --" >&2 if [ "${1:0:5}" = "file:" ] then # file: pattern local _FILE=${1#"file:"} [ -r "$_FILE" ] return elif tool wget then # wget exists wget --spider "$1" 2>/dev/null return elif tool curl then # try curl curl -L --output /dev/null --silent --fail -r 0-0 "$1" return fi echo "error: can't fetch files (please install 'wget' or 'curl')" >&2 return 1 } function fetch() { # $url $dest - make sure that $dest exists only on success $DEBUG && echo "-- fetch $1 $2 --" >&2 if $DRYRUN then echo "fetch $1 -> $2" >&2 elif [ "${1:0:5}" = "file:" ] then # file: pattern local _FILE=${1#"file:"} if [ "$2" = "-" ] then # to stdout $DEBUG && echo "-- cat $_FILE --" >&2 cat $_FILE else $DEBUG && echo "-- cp $_FILE $2 --" >&2 cp $_FILE $2 || rm "$2" fi elif tool wget then # wget exists if [ "$2" = "-" ] then # to stdout $DEBUG && echo "-- wget -O - $1 --" >&2 wget -O - "$1" else $DEBUG && echo "-- wget -O - $1 >$2 --" >&2 wget -O - "$1" >"$2" || rm "$2" fi elif tool curl then # try curl if [ "$2" = "-" ] then # to stdout $DEBUG && echo "-- curl $1 --" >&2 curl -L "$1" else $DEBUG && echo "-- curl $1 -o $2 --" >&2 curl -L "$1" -o "$2" || rm "$2" fi else echo "error: can't fetch files (please install 'wget' or 'curl')" >&2 exit 1 fi } function partitions() { # print partition table local P if [ "$DDLIST" ] then echo "$DDLIST" | while read SECTOR FILE do [ "$SECTOR" ] && echo "-: s:$SECTOR dd:$FILE" done fi for P in 1 2 3 4 do FORMAT="$(getparam "$P" FORMAT)" PS="$(getparam $P PSTART)" SIZE="$(getparam "$P" SIZE)" [ "$FORMAT" = none ] && SIZE=0 BOOT="$(getparam "$P" BOOT)" [ "$BOOT" != none ] && BOOT="$(dirname "$BOOT")/*" # remove u-boot.bin and replace BOOTDIR=/"$(getparam "$P" BOOTDIR)" KERNEL="$(getparam "$P" KERNEL)" KERNELDIR="/$(getparam "$P" KERNELDIR)" DT="$(getparam "$P" DT)" DTDIR="/$(getparam "$P" DTDIR)" ROOTFS="$(getparam "$P" ROOTFS)" MODULES="$(getparam "$P" MODULES)" CONFIG="$(getparam "$P" CONFIG)" PNAME="$(getparam "$P" NAME)" echo "$P: $FORMAT p:$PS s:$SIZE% n:$PNAME b:$BOOTDIR+$BOOT k:$KERNELDIR+$KERNEL dt:$DTDIR+$DT r:$ROOTFS m:$MODULES c:$CONFIG" XLIST="$(getparam "$P" XLIST)" [ "$XLIST" ] && echo "$P: x:$(echo $XLIST)" done } # https://stackoverflow.com/questions/4023830/how-to-compare-two-strings-in-dot-separated-version-format-in-bash function version { printf "%03d" $(echo "$1.2.0.0.0" | cut -d '.' -f 1-5 | tr '.' ' ') } function sane_sfdisk { SFVER=$(export LC_ALL=C LANGUAGE=C; sfdisk -v | awk '{print $4}') $DEBUG && echo $(which sfdisk) -v: $(export LC_ALL=C LANGUAGE=C; sfdisk -v) >&2 $DEBUG && echo "$(version $SFVER) -ge $(version 2.26)" >&2 if [ "$(version $SFVER)" -ge "$(version 2.26)" ] then # 2.26.2 and later have changed API # compare to http://linux-sunxi.org/Bootable_SD_card#Partitioning # -L is deprecated and default # -uS is default now and deprecated # --in-order is gone and default # -R is removed sfdisk "$@" else sfdisk --in-order --Linux -uS "$@" fi } function disk_size { # make sure fdisk runs in default LANGUAGE ( export LC_ALL=C LANGUAGE=C; fdisk -l "$1" ) | fgrep " $1: " | head -1 | awk '{print $5}' # expr 1024 '*' $(sane_sfdisk -s "$DEV") # total size in bytes - but why 1024? is this well defined? } ### here starts real processing ### for TOOL in sfdisk fdisk partprobe dd mkfs.vfat mke2fs fsck.vfat fsck.ext3 fsck wget bzip2 tar do [ $(which $TOOL) ] || { echo "please install '$TOOL' (apt-get install util-linux)" >&2; exit 1; } done setparam 2 KERNEL 1234 _TESTME=$(getparam 2 KERNEL) if [ "$_TESTME" != 1234 ] then echo "error: getparam and setparam did not pass internal test - please check shell or script" >&2 set exit fi unset _TESTME while [ "$1" ] do case "$1" in "-a" ) # list all macros macros | while read MACRO COMMAND do case "$MACRO" in '' | '#' | '#'* ) continue;; # comment -* | '*' ) continue;; # pattern * ) echo "$MACRO";; esac done | sort exit ;; "-i" | "--no-format" ) NOFORMAT=yes ;; "-u" | "--update" ) # self-update $DEBUG && echo "-- self-update --" >&2 if ! exists "https://git.goldelico.com/?p=gta04-makesd.git;a=blob_plain;hb=HEAD;f=$(basename $0)" then echo "!!! can't access download path https://git.goldelico.com/?p=gta04-makesd.git;a=blob_plain;hb=HEAD;f=$(basename $0)" >&2 exit 1 fi fetch "https://git.goldelico.com/?p=gta04-makesd.git;a=blob_plain;hb=HEAD;f=$(basename $0)" "$0.new" && chmod +x $0.new && mv $0.new $0 exit ;; "--debug" ) DEBUG=true ;; "--dry" ) DRYRUN=true ;; "--help" ) useage exit ;; * ) break ;; esac shift done $DEBUG && echo "-- define defaults --" >&2 NP=0 rm -f .makesd.log process -f none -f none -f none -f none if [ "$1" ] then $DEBUG && echo "-- start over with given options --" >&2 # start over with given options NP=0 rm -f .makesd.log process "$@" || exit 1 fi partitions $DEBUG && echo "-- prepare $DEV --" >&2 if [ "${DEV}" = "/dev/sda" ] then echo "error: refuses to overwrite /dev/sda - but you may specify /dev/sda!" >&2 exit 1 fi [ "${DEV}" = "/dev/sda!" ] && DEV="/dev/sda" # override protection if ! [ -b "$DEV" ] && ! $DRYRUN then echo "error: not a block device: $DEV" >&2 echo " either edit echo /dev/device > ~/.makesd.conf" >&2 echo " or pass DEV=/dev/device" >&2 exit 1 fi if ! [ -w "$DEV" ] && ! $DRYRUN then echo "error: you do not have write permission for: $DEV" >&2 echo "Maybe you should run as root - but beware you may loose all data if you choose the wrong device!" >&2 exit 1 fi DEVP=$DEV if [ -b "${DEV}p1" ] || expr "${DEV}" : "/dev/mmc.*" >/dev/null then DEVP=${DEV}p # MMC card reader expects "p"artition suffix (hard coded into kernel) $DEBUG && echo "-- suffix p added --" >&2 fi $DEBUG && echo "-- unmount partitions --" >&2 function totalsize() { # also create mount points! local P TOTALSIZE=0 for P in 1 2 3 4 do umount -f ${DEVP}${P} 2>/dev/null wait case "$(getparam $P FORMAT)" in none ) ## check if this is the last or only followed by "none" ## i.e. there can't be "holes" in the partition numbers ;; # skip fat* | ext* | swap ) ! $DRYRUN && mkdir -p /media/P${P} TOTALSIZE=$(expr "$TOTALSIZE" + "$(getparam $P SIZE)") # sum up ;; * ) echo "error: invalid partition type '$(getparam $P FORMAT)' for partition $P" >&2 exit 1 ;; esac done } # make sure we are not mounted anywhere else umount ${DEV}* sleep 2 umount ${DEV}* totalsize ls -l /media/P[1-4] $DEBUG && echo "-- total size $TOTALSIZE --" >&2 if ! [ "$NOFORMAT" ] then $DEBUG && echo "-- clear boot record --" >&2 if ! $DRYRUN then dd if=/dev/zero of=$DEV bs=1024 count=1024 # clear boot records dd if=/dev/urandom bs=1 count=4 seek=440 of=$DEV # write a fresh random unique disk identifier (MBR) fi ## the following code is roughly ## based on: http://omappedia.org/wiki/SD_Configuration#Script_to_partition.2Fformat_SDCards ## and: http://www.sakoman.com/OMAP/a-script-for-partitioningformatting-a-bootable-sdmicrosd-card.html $DEBUG && echo "-- partitioning --" >&2 function sfdisk_table() { # run in an anonymous function, not a subprocess TS=$TOTALSIZE # save for next call SIZE=$(disk_size "$DEV") $DEBUG && echo "-- DISK SIZE: $SIZE bytes --" >&2 [ "$SIZE" ] || { echo "error: can't determine size of disk $DEV" >&2; exit 1; } TOTALSECTORS=$(expr "$SIZE" / 512) $DEBUG && echo "-- TOTAL SECTORS: $TOTALSECTORS --" >&2 SECTORS=63 HEADS=255 CYLINDERS=$(expr "$TOTALSECTORS" / "$HEADS" / "$SECTORS") $DEBUG && echo "-- CYLINDERS: $CYLINDERS --" >&2 SECTORSPERCYLINDER=$(expr "$TOTALSECTORS" / "$CYLINDERS") $DEBUG && echo "-- SECTORS PER CYLINDER: $SECTORSPERCYLINDER --" >&2 PSTART=128 local P for P in 1 2 3 4 do # calculate sizes of partitions FORMAT=$(getparam $P FORMAT) PS=$(getparam $P PSTART) [ "$PS" ] || PS=$PSTART REMAINING=$(expr "$TOTALSECTORS" - "$PS") THISSIZE=$(getparam $P SIZE) [ "$FORMAT" = none ] && THISSIZE=0 # overwrite (has not been counted for TOTALSIZE) if [ "$THISSIZE" = "$TOTALSIZE" ] then # last partition PSECTORS="$REMAINING" # take all remaining sectors elif [ "$TOTALSIZE" -gt 0 ] then # intermediate partition PE=$(getparam $(expr $P + 1) PSTART) if [ "$PE" ] then # next sector has specified explicit start PSECTORS=$(expr "$PE" - "$PSTART") else PSECTORS=$(expr \( "$REMAINING" '*' "$THISSIZE" \) / "$TOTALSIZE") fi # S1=$PSECTORS # echo "S1: $S1" >&2 # S2=$(expr "$PSTART" + "$S1" + "$SECTORSPERCYLINDER" - 1 ) # echo "S2: $S2" >&2 # S3=$(expr "$S2" / "$SECTORSPERCYLINDER" ) # echo "S3: $S3" >&2 # PSECTORS=$(expr \( \( "$PSTART" + "$PSECTORS" + "$SECTORSPERCYLINDER" - 1 \) / "$SECTORSPERCYLINDER" \) "*" "$SECTORSPERCYLINDER" - "$PSTART") # round up to end of full cylinder boundary else PSECTORS=0 # must be a "none" fi TOTALSIZE=$(expr "$TOTALSIZE" - "$THISSIZE") # this is not exactly correct PSTART=$(expr "$PS" + "$PSECTORS") # calculated start of next partition if $DEBUG then echo "P: $P" >&2 echo "PSTART: $(getparam $P PSTART)" >&2 echo "FORMAT: $FORMAT" >&2 echo "REMAINING: $REMAINING" >&2 echo "THISSIZE: $THISSIZE ($TOTALSIZE)" >&2 echo "SECTORS: $PS + $PSECTORS .. $PSTART" >&2 fi # FIXME: use "Named-fields format" to specify data for a specific partition # e.g. $P: start=$PS,size=$PSECTORS,type=0c,bootable # e.g. $P: start=$PS,size=$PSECTORS,type=83 # but sfdisk in Debian Jessie does not yet understand case "$FORMAT" in none ) : skip # (how with sfdisk? do we have to read the current partition sizes) # this gives the wrong impression that we could define just a partition 3 and none for 1 & 2 # in other words: there should only be "none" records after the first "none" # but we don't check that yet SFVER=$(export LC_ALL=C LANGUAGE=C; sfdisk -v | awk '{print $4}') if [ "$(version $SFVER)" -lt "$(version 2.26)" ] then echo "$PS,0,0,-" # start with empty partition before 2.26 fi ;; fat* ) # echo "$P: start=$PSTART,size=$PSECTORS,type=0c,bootable" # FAT partition (bootable) echo "$PS,$PSECTORS,0x0C,*" # FAT partition (bootable) ;; ext* ) # echo "$P: start=$PSTART,size=$PSECTORS,type=83" # Linux partition echo "$PS,$PSECTORS,83,-" # Linux partition ;; swap ) ## echo "$P: start=$PSTART,size=$PSECTORS,type=82" # Linux swap partition echo "$PS,$PSECTORS,82,-" # Linux swap partition ;; esac done if [ "$TOTALSIZE" != 0 -o "$REMAINING" != 0 ] then echo "error: error in partition calculation" >&2 echo "TOTALSIZE: $TOTALSIZE" >&2 echo "REMAINING: $REMAINING" >&2 echo "did yo specify 4 empty partitions?" >&2 exit 1 fi TOTALSIZE=$TS # restore for next call } if $DRYRUN then sfdisk_table >&2 else $DEBUG && sfdisk_table >&2 sfdisk_table | sane_sfdisk --force "$DEV" || exit sleep 2 # this may try to remount! [ -x /sbin/partprobe ] && /sbin/partprobe "$DEV" # alternative? blockdev --rereadpt "$DEV" sleep 2 fi # fdisk -l "$DEV" $DEBUG && echo "-- format partitions --" >&2 fi # ! NOFORMAT FATNUM="" EXTNUM="" SWAPNUM="" for P in 1 2 3 4 do # format and mount partitions if $DRYRUN then $DEBUG && echo "-- format ${DEVP}${P} as $(getparam $P FORMAT) --" >&2 continue fi umount ${DEVP}${P} 2>/dev/null sleep 1 PNAME="$(getparam $P NAME)" case "$(getparam $P FORMAT)" in none ) : skip ;; fat* ) if ! [ "$NOFORMAT" ] then echo making $(getparam $P FORMAT) partition $PNAME case "$(getparam $P FORMAT)" in fat16 ) mkfs.vfat -F 16 -n "$PNAME" ${DEVP}${P} && fsck.vfat -a -y ${DEVP}${P} ;; fat | fat32 ) mkfs.vfat -F 32 -n "$PNAME" ${DEVP}${P} && fsck.vfat -a -y ${DEVP}${P} ;; fat ) # let mkfs decide mkfs.vfat -n "$PNAME" ${DEVP}${P} && fsck.vfat -a -y ${DEVP}${P} ;; esac fi mount ${DEVP}${P} /media/P${P} || exit ;; ext* ) if ! [ "$NOFORMAT" ] then echo making $(getparam $P FORMAT) partition $PNAME case "$(getparam $P FORMAT)" in ext2 ) yes | mke2fs -t ext2 -L "${PNAME}" ${DEVP}${P} && fsck.ext2 -y ${DEVP}${P} ;; ext3 ) yes | mke2fs -t ext3 -j -L "${PNAME}" ${DEVP}${P} && fsck.ext3 -y ${DEVP}${P} ;; ext4 ) yes | mke2fs -t ext4 -j -L "${PNAME}" ${DEVP}${P} && fsck.ext4 -y ${DEVP}${P} ;; esac fi mount ${DEVP}${P} /media/P${P} || exit ;; swap ) mkswap -L "$PNAME" ${DEVP}${P} ;; esac done df # should have been formatted and mounted now $DEBUG && echo "-- variables --" >&2 $DEBUG && set >&2 $DEBUG && echo "-- install --" >&2 KERNEL_VERSION="" $DEBUG && echo "-- process -dd --" >&2 if [ "$DDLIST" ] then echo "$DDLIST" | while read SECTOR FILE do if [ "$SECTOR" ] then $DEBUG && echo "-- fetch $FILE to sector $SECTOR --" >&2 ! $DRYRUN && fetch "$FILE" - | dd of=$DEV bs=512 seek=$SECTOR fi done fi for P in 1 2 3 4 do FORMAT=$(getparam "$P" FORMAT) $DEBUG && echo "-- process partition $P with format $FORMAT --" >&2 if [ "$FORMAT" = "none" -o "$FORMAT" = "swap" ] then continue # skip fi if [ ! -d /media/P${P} ] then echo "-- partition /media/P${P} not mounted --" >&2 fi ROOTFS=$(getparam "$P" ROOTFS) if [ "$ROOTFS" != none ] then # a rootfs must be installed first so that we can overwrite by a kernel $DEBUG && echo "-- fetch rootfs to /media/P${P} --" >&2 ls -l /media/P${P} # run in a subshell so that we can really redirect ouput exists "$ROOTFS" || { echo "!! could not find $ROOTFS" >&2; exit 1; } case "$ROOTFS" in *.tgz | *.tar.gz ) fetch "$ROOTFS" - | ( cd "/media/P${P}" && tar xvzf - --numeric-owner ) ;; *.tbz | *.tar.bz2 ) fetch "$ROOTFS" - | ( cd "/media/P${P}" && tar xvjf - --numeric-owner ) ;; * ) echo "-- don't know how to unpack $ROOTFS --" >&2; exit ;; esac case "$(cat /media/P${P}/etc/debian_version 2>/dev/null)" in [1-8].* ) echo "-- tuning partition ${DEVP}${P} to be compatible with older Debian fsck --" umount ${DEVP}${P} 2>/dev/null # echo tune2fs -O ^has_journal ${DEVP}${P} yes | tune2fs -O ^has_journal ${DEVP}${P} # echo fsck -fy ${DEVP}${P} # must run fsck first to reset some counter or tune2fs would fail fsck -fy ${DEVP}${P} # echo tune2fs -O ^metadata_csum ${DEVP}${P} yes | tune2fs -O ^metadata_csum ${DEVP}${P} # echo mount ${DEVP}${P} /media/P${P} mount ${DEVP}${P} /media/P${P} ;; [9].* | [1-9][0-9].* ) ;; esac fi BOOT=$(getparam "$P" BOOT) BOOTDIR="/media/P${P}/$(getparam "$P" BOOTDIR)/" if [ "$BOOT" != none ] then $DEBUG && echo "-- fetch boot loader to $BOOTDIR --" >&2 mkdir -p "$BOOTDIR" || exit # # loading some files may fail since they do not exist for the chosen variant - but we ignore # # should somehow count how much files have been installed # and print an error if none... # FIXME: there should be a default list and a macro to define them ( DIR="$(dirname "$BOOT")" echo "$DIR/MLO" "$BOOTDIR/MLO" # must come first echo "$DIR/x-load.flash" "$BOOTDIR/x-load.flash" echo "$DIR/MLO.flash" "$BOOTDIR/MLO.flash" echo "$BOOT" "$BOOTDIR/u-boot.bin" echo "$DIR/u-boot.img" "$BOOTDIR/u-boot.img" # some x-loaders want u-boot.bin others want u-boot.img (e.g. the OMAP5 MLO) echo "$DIR/u-boot.flash" "$BOOTDIR/u-boot.flash" echo "$DIR/u-boot.img.flash" "$BOOTDIR/u-boot.img.flash" echo "$DIR/uImage" "$BOOTDIR/uImage" # for chained intermediate u-boot hiding behind the name uImage echo "$DIR/splash.rgb16z" "$BOOTDIR/splash.rgb16z" echo "$DIR/menu.rgb16z" "$BOOTDIR/menu.rgb16z" echo "$DIR/boot.scr" "$BOOTDIR/boot.scr" echo "$DIR/boot.txt" "$BOOTDIR/boot.txt" echo "$DIR/uEnv.txt" "$BOOTDIR/uEnv.txt" echo "$DIR/boot.bin" "$BOOTDIR/BOOT.BIN" # for SAMA5 echo "$DIR/uboot.env" "$BOOTDIR/uboot.env" # for SAMA5 ) | while read DIR DEST do if exists "$DIR" then fetch "$DIR" "$DEST" || break fi done ! $DRYRUN && { echo "$CMDLINE"; date; partitions; } >"$BOOTDIR/makesd.info" # so that we can easily find out for which device this is formatted, when and how fi KERNEL=$(getparam "$P" KERNEL) KERNELDIR="/media/P${P}/$(getparam "$P" KERNELDIR)/" if [ "$KERNEL" != none ] then $DEBUG && echo "-- fetch kernel to $KERNELDIR --" >&2 mkdir -p "$KERNELDIR" KDEST="$KERNELDIR/$(basename "$KERNEL")" exists "$KERNEL" || { echo "could not find $KERNEL" >&2; exit 1; } fetch "$KERNEL" "$KDEST" BOOTARGS="$(dirname "$KERNEL")/bootargs.scr" exists "$BOOTARGS" && fetch "$BOOTARGS" "$KERNELDIR/bootargs.scr" KERNEL_VERSION=$(file "$KDEST") KERNEL_VERSION=$(expr "$KERNEL_VERSION" : ".*Linux-\([^,]*\),.*") $DEBUG && echo "-- installed $KERNEL_VERSION --" >&2 fi DT=$(getparam "$P" DT) DTDIR="/media/P${P}/$(getparam "$P" DTDIR)/" if [ "$DT" != none ] then $DEBUG && echo "-- fetch device trees to $DTDIR --" >&2 mkdir -p "$DTDIR" exists "$DT" || { echo "could not find $DT" >&2; exit 1; } fetch "$DT" - | ( cd "$DTDIR" && tar xvjf - --no-same-owner) fi MODULES=$(getparam "$P" MODULES) if [ "$MODULES" != none ] then $DEBUG && echo "-- fetch modules to /media/P${P} --" >&2 exists "$MODULES" || { echo "could not find $MODULES" >&2; exit 1; } fetch "$MODULES" - | (cd "/media/P${P}/" && tar xvzf - --numeric-owner --keep-directory-symlink) if [ "$KERNEL_VERSION" ] && tool depmod then # run depmod on the installed root for the last kernel we have installed $DEBUG && echo "-- run depmod $KERNEL_VERSION --" >&2 depmod -b "/media/P${P}/" "$KERNEL_VERSION" fi fi CONFIG=$(getparam "$P" CONFIG) if [ "$CONFIG" != none ] then $DEBUG && echo "-- fetch config patches to /media/P${P} --" >&2 exists "$CONFIG" || { echo "could not find $CONFIG" >&2; exit 1; } fetch "$CONFIG" - | (cd "/media/P${P}/" && tar xvzf - --numeric-owner) fi XLIST="$(getparam $P XLIST)" $DEBUG && echo "-- x: $(echo $XLIST) --" >&2 echo "$XLIST" | while read DIRFILE URL do if [ ! "$URL" ] then continue fi $DEBUG && echo "-- fetch file(s) $URL to /media/P${P}/$DIRFILE --" >&2 # FIXME: error if none did match for SUFFIX in .tgz .tbz '' do FILE="$URL$SUFFIX" exists "$FILE" || continue case "$FILE" in *.tgz ) fetch "$FILE" - | (mkdir -p "/media/P${P}/$DIRFILE" && cd "/media/P${P}/$DIRFILE" && tar xvzf - --numeric-owner) && break;; # try to unpack into directory *.tbz ) fetch "$FILE" - | (mkdir -p "/media/P${P}/$DIRFILE" && cd "/media/P${P}/$DIRFILE" && tar xvjf - --numeric-owner) && break;; # try to unpack into directory * ) # if DIRFILE ends in / use basename of url # if not, use as qualified file name case "$DIRFILE" in */ ) mkdir -p "/media/P${P}/$DIRFILE" && fetch "$FILE" "/media/P${P}/$DIRFILE$(basename "$FILE")" && break;; # load single file * ) mkdir -p "$(dirname "$/media/P${P}/DIRFILE")" && fetch "$FILE" "/media/P${P}/$DIRFILE" && break;; # load plain file (with rename) esac ;; esac done done INFO="$(getparam $P INFO)" if [ "$INFO" ] then $DEBUG && echo "-- write info >/media/P${P}/makesd.info --" >&2 ! $DRYRUN && ( echo "+++ this system was created by makesd (https://projects.goldelico.com/p/gta04-makesd/) at $(date) +++" echo "$CMDLINE" partitions ) >"/media/P${P}/makesd.info" # so that we can easily find out for which device this is formatted fi ls -l /media/P[1-4] done # loop over partitions $DEBUG && echo "-- sync --" >&2 sync if [ "$DEV" ] then $DEBUG && echo "-- show mounted partitions --" >&2 df $DEBUG && echo "-- unmount --" >&2 for P in 1 2 3 4 do sync [ -r "/media/P${P}/u-boot.img" ] && file "/media/P${P}/u-boot.img" [ -r "/media/P${P}/uImage" ] && file "/media/P${P}/uImage" umount ${DEVP}${P} 2>/dev/null [ -d "/media/P${P}" ] && rmdir "/media/P${P}" done $DEBUG && echo "-- fsck --" >&2 for P in 1 2 3 4 do if [ -b "${DEVP}${P}" ] then echo "${DEVP}${P}" = $(fsck -T -a -f "${DEVP}${P}") fi done fi $DEBUG && echo "-- done --" >&2