1#!/bin/sh -e
2#
3# Copyright (c) 2012, Intel Corporation.
4# All rights reserved.
5#
6# install.sh [device_name] [rootfs_name]
7#
8
9PATH=/sbin:/bin:/usr/sbin:/usr/bin
10
11# figure out how big of a boot partition we need
12boot_size=$(du -ms /run/media/$1/ | awk '{print $1}')
13# remove rootfs.img ($2) from the size if it exists, as its not installed to /boot
14if [ -e /run/media/$1/$2 ]; then
15    boot_size=$(( boot_size - $( du -ms /run/media/$1/$2 | awk '{print $1}') ))
16fi
17# remove initrd from size since its not currently installed
18if [ -e /run/media/$1/initrd ]; then
19    boot_size=$(( boot_size - $( du -ms /run/media/$1/initrd | awk '{print $1}') ))
20fi
21# add 10M to provide some extra space for users and account
22# for rounding in the above subtractions
23boot_size=$(( boot_size + 10 ))
24
25# 5% for swap
26swap_ratio=5
27
28# Get a list of hard drives
29hdnamelist=""
30live_dev_name=`cat /proc/mounts | grep ${1%/} | awk '{print $1}'`
31live_dev_name=${live_dev_name#\/dev/}
32# Only strip the digit identifier if the device is not an mmc
33case $live_dev_name in
34    mmcblk*)
35    ;;
36    nvme*)
37    ;;
38    *)
39        live_dev_name=${live_dev_name%%[0-9]*}
40    ;;
41esac
42
43echo "Searching for hard drives ..."
44
45# Some eMMC devices have special sub devices such as mmcblk0boot0 etc
46# we're currently only interested in the root device so pick them wisely
47devices=`ls /sys/block/ | grep -v mmcblk` || true
48mmc_devices=`ls /sys/block/ | grep "mmcblk[0-9]\{1,\}$"` || true
49devices="$devices $mmc_devices"
50
51for device in $devices; do
52    case $device in
53        loop*)
54            # skip loop device
55            ;;
56        sr*)
57            # skip CDROM device
58            ;;
59        ram*)
60            # skip ram device
61            ;;
62        *)
63            # skip the device LiveOS is on
64            # Add valid hard drive name to the list
65            case $device in
66                $live_dev_name*)
67                # skip the device we are running from
68                ;;
69                *)
70                    hdnamelist="$hdnamelist $device"
71                ;;
72            esac
73            ;;
74    esac
75done
76
77if [ -z "${hdnamelist}" ]; then
78    echo "You need another device (besides the live device /dev/${live_dev_name}) to install the image. Installation aborted."
79    exit 1
80fi
81
82TARGET_DEVICE_NAME=""
83for hdname in $hdnamelist; do
84    # Display found hard drives and their basic info
85    echo "-------------------------------"
86    echo /dev/$hdname
87    if [ -r /sys/block/$hdname/device/vendor ]; then
88        echo -n "VENDOR="
89        cat /sys/block/$hdname/device/vendor
90    fi
91    if [ -r /sys/block/$hdname/device/model ]; then
92        echo -n "MODEL="
93        cat /sys/block/$hdname/device/model
94    fi
95    if [ -r /sys/block/$hdname/device/uevent ]; then
96        echo -n "UEVENT="
97        cat /sys/block/$hdname/device/uevent
98    fi
99    echo
100done
101
102# Get user choice
103while true; do
104    echo "Please select an install target or press n to exit ($hdnamelist ): "
105    read answer
106    if [ "$answer" = "n" ]; then
107        echo "Installation manually aborted."
108        exit 1
109    fi
110    for hdname in $hdnamelist; do
111        if [ "$answer" = "$hdname" ]; then
112            TARGET_DEVICE_NAME=$answer
113            break
114        fi
115    done
116    if [ -n "$TARGET_DEVICE_NAME" ]; then
117        break
118    fi
119done
120
121if [ -n "$TARGET_DEVICE_NAME" ]; then
122    echo "Installing image on /dev/$TARGET_DEVICE_NAME ..."
123else
124    echo "No hard drive selected. Installation aborted."
125    exit 1
126fi
127
128device=/dev/$TARGET_DEVICE_NAME
129
130#
131# The udev automounter can cause pain here, kill it
132#
133rm -f /etc/udev/rules.d/automount.rules
134rm -f /etc/udev/scripts/mount*
135
136#
137# Unmount anything the automounter had mounted
138#
139umount ${device}* 2> /dev/null || /bin/true
140
141mkdir -p /tmp
142
143# Create /etc/mtab if not present
144if [ ! -e /etc/mtab ] && [ -e /proc/mounts ]; then
145    ln -sf /proc/mounts /etc/mtab
146fi
147
148disk_size=$(parted ${device} unit mb print | grep '^Disk .*: .*MB' | cut -d" " -f 3 | sed -e "s/MB//")
149
150swap_size=$((disk_size*swap_ratio/100))
151rootfs_size=$((disk_size-boot_size-swap_size))
152
153rootfs_start=$((boot_size))
154rootfs_end=$((rootfs_start+rootfs_size))
155swap_start=$((rootfs_end))
156
157# MMC devices are special in a couple of ways
158# 1) they use a partition prefix character 'p'
159# 2) they are detected asynchronously (need rootwait)
160rootwait=""
161part_prefix=""
162if [ ! "${device#/dev/mmcblk}" = "${device}" ] || \
163   [ ! "${device#/dev/nvme}" = "${device}" ]; then
164    part_prefix="p"
165    rootwait="rootwait"
166fi
167
168# USB devices also require rootwait
169if [ -n `readlink /dev/disk/by-id/usb* | grep $TARGET_DEVICE_NAME` ]; then
170    rootwait="rootwait"
171fi
172
173bootfs=${device}${part_prefix}1
174rootfs=${device}${part_prefix}2
175swap=${device}${part_prefix}3
176
177echo "*****************"
178echo "Boot partition size:   $boot_size MB ($bootfs)"
179echo "Rootfs partition size: $rootfs_size MB ($rootfs)"
180echo "Swap partition size:   $swap_size MB ($swap)"
181echo "*****************"
182echo "Deleting partition table on ${device} ..."
183dd if=/dev/zero of=${device} bs=512 count=35
184
185echo "Creating new partition table on ${device} ..."
186parted ${device} mklabel gpt
187
188echo "Creating boot partition on $bootfs"
189parted ${device} mkpart boot fat32 0% $boot_size
190parted ${device} set 1 boot on
191
192echo "Creating rootfs partition on $rootfs"
193parted ${device} mkpart root ext4 $rootfs_start $rootfs_end
194
195echo "Creating swap partition on $swap"
196parted ${device} mkpart swap linux-swap $swap_start 100%
197
198parted ${device} print
199
200echo "Waiting for device nodes..."
201C=0
202while [ $C -ne 3 ] && [ ! -e $bootfs  -o ! -e $rootfs -o ! -e $swap ]; do
203    C=$(( C + 1 ))
204    sleep 1
205done
206
207echo "Formatting $bootfs to vfat..."
208mkfs.vfat $bootfs
209
210echo "Formatting $rootfs to ext4..."
211mkfs.ext4 $rootfs
212
213echo "Formatting swap partition...($swap)"
214mkswap $swap
215
216mkdir /tgt_root
217mkdir /src_root
218mkdir -p /boot
219
220# Handling of the target root partition
221mount $rootfs /tgt_root
222mount -o rw,loop,noatime,nodiratime /run/media/$1/$2 /src_root
223echo "Copying rootfs files..."
224cp -a /src_root/* /tgt_root
225if [ -d /tgt_root/etc/ ] ; then
226    boot_uuid=$(blkid -o value -s UUID ${bootfs})
227    swap_part_uuid=$(blkid -o value -s PARTUUID ${swap})
228    echo "/dev/disk/by-partuuid/$swap_part_uuid                swap             swap       defaults              0  0" >> /tgt_root/etc/fstab
229    echo "UUID=$boot_uuid              /boot            vfat       defaults              1  2" >> /tgt_root/etc/fstab
230    # We dont want udev to mount our root device while we're booting...
231    if [ -d /tgt_root/etc/udev/ ] ; then
232        echo "${device}" >> /tgt_root/etc/udev/mount.blacklist
233    fi
234fi
235
236umount /src_root
237
238# Handling of the target boot partition
239mount $bootfs /boot
240echo "Preparing boot partition..."
241
242EFIDIR="/boot/EFI/BOOT"
243mkdir -p $EFIDIR
244# Copy the efi loader
245cp /run/media/$1/EFI/BOOT/*.efi $EFIDIR
246
247if [ -f /run/media/$1/EFI/BOOT/grub.cfg ]; then
248    root_part_uuid=$(blkid -o value -s PARTUUID ${rootfs})
249    GRUBCFG="$EFIDIR/grub.cfg"
250    cp /run/media/$1/EFI/BOOT/grub.cfg $GRUBCFG
251    # Update grub config for the installed image
252    # Delete the install entry
253    sed -i "/menuentry 'install'/,/^}/d" $GRUBCFG
254    # Delete the initrd lines
255    sed -i "/initrd /d" $GRUBCFG
256    # Delete any LABEL= strings
257    sed -i "s/ LABEL=[^ ]*/ /" $GRUBCFG
258    # Replace root= and add additional standard boot options
259    # We use root as a sentinel value, as vmlinuz is no longer guaranteed
260    sed -i "s/ root=[^ ]*/ root=PARTUUID=$root_part_uuid rw $rootwait quiet /g" $GRUBCFG
261fi
262
263if [ -d /run/media/$1/loader ]; then
264    rootuuid=$(blkid -o value -s PARTUUID ${rootfs})
265    SYSTEMDBOOT_CFGS="/boot/loader/entries/*.conf"
266    # copy config files for systemd-boot
267    cp -dr /run/media/$1/loader /boot
268    # delete the install entry
269    rm -f /boot/loader/entries/install.conf
270    # delete the initrd lines
271    sed -i "/initrd /d" $SYSTEMDBOOT_CFGS
272    # delete any LABEL= strings
273    sed -i "s/ LABEL=[^ ]*/ /" $SYSTEMDBOOT_CFGS
274    # delete any root= strings
275    sed -i "s/ root=[^ ]*/ /" $SYSTEMDBOOT_CFGS
276    # add the root= and other standard boot options
277    sed -i "s@options *@options root=PARTUUID=$rootuuid rw $rootwait quiet @" $SYSTEMDBOOT_CFGS
278fi
279
280umount /tgt_root
281
282# copy any extra files needed for ESP
283if [ -d /run/media/$1/esp ]; then
284    cp -r /run/media/$1/esp/* /boot
285fi
286
287# Copy kernel artifacts. To add more artifacts just add to types
288# For now just support kernel types already being used by something in OE-core
289for types in bzImage zImage vmlinux vmlinuz fitImage; do
290    for kernel in `find /run/media/$1/ -name $types*`; do
291        cp $kernel /boot
292    done
293done
294
295umount /boot
296
297sync
298
299echo "Installation successful. Remove your installation media and press ENTER to reboot."
300
301read enter
302
303echo "Rebooting..."
304reboot -f
305