]> git.friedersdorff.com Git - max/disk_creator.git/blob - disk_creator.sh
More explicit bash
[max/disk_creator.git] / disk_creator.sh
1 #!/bin/bash
2 # Copyright 2019 Maximilian Friedersdorff
3 #
4 # This file is part of 'disk_creator.sh'
5 #
6 # 'disk_creator.sh' is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
10 #
11 # Foobar is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with Foobar.  If not, see <https://www.gnu.org/licenses/>.
18
19 usage() {
20         echo "Usage:"
21         echo "disk_creator.sh OS_IMAGE USB_DRIVE"
22         echo
23         echo "Example:"
24         echo "disk_creator.sh ~/Downloads/xubuntu-18.04.2-desktop-amd64.iso /dev/sdd"
25         echo
26         echo "Create a live usb drive on the device '/dev/sdd' with the os found in"
27         echo "~/Downloads/xubuntu-18.04.2-desktop-amd64.iso"
28 }
29
30 if [ $# -ne 2 ]; then
31         echo "ERROR: expected exactly 2 arguments"
32         usage
33         exit 1
34 fi
35
36 if [ ! -b $2 ]; then
37         echo "ERROR: $2 is not a block device"
38         usage
39         exit 1
40 fi
41
42 if [ ! -f $1 ]; then
43         echo "ERROR: $1 is not a regular file"
44         usage
45         exit 1
46 fi
47
48 # The name of the USB drive you want to create
49 usb_drive="$2"
50
51 # The location of the linux distribution you want to use
52 os_image="$1"
53
54 # Removing leading directory/folder name
55 image_name="${os_image##*/}"
56 # Removing the filename extension
57 os_name="$(echo ${image_name%.*} | tr '-' ' ' | tr '_' ' ')"
58
59 # Querying the block size, the logical size of entities on the USB drive
60 block_size=$(cat /sys/block/${usb_drive#/dev/}/queue/hw_sector_size)
61
62 # Calculate the size of the partition to hold the iso and boot loader.  Allow
63 # 50MiB for the bootloader (this is way overkill).
64 live_part_size="$(ls -l ${os_image} | 
65         awk -v block_size=${block_size} \
66         '{print (($5/block_size) + (50*1024*1024/block_size))}')"
67
68 # Calculate the start of the 'usbdata' partition
69 let usbdata_part_start="${live_part_size} + 2048 + 3*1024*1024*1024/${block_size}"
70
71 main() {
72         # Find out the location of the linux kernel and the initramfs (initial ramdisk
73         # file system) in the os image file. We need these locations later when 
74         # configuring grub
75         modprobe loop
76         loop_dev="$(losetup --show -f ${os_image})"
77         l_mount="$(mktemp -d)"
78         mount -o ro "${loop_dev}" "${l_mount}"
79         kernel="$(find ${l_mount} -iname *vmlinuz* -printf '%P\n')"
80         initramfs="$(find ${l_mount} -iname *initr* -printf '%P\n')"
81         umount "${l_mount}"
82         rmdir "${l_mount}"
83         losetup -d "${loop_dev}"
84
85         if [ $(echo "${kernel}" | wc -l) -gt 1 ]; then
86                 echo "Too many possible linux kernels found:"
87                 echo $kernel
88         fi
89
90         if [ $(echo "${initramfs}" | wc -l) -gt 1 ]; then
91                 echo "Too many possible initramfs found:"
92                 echo $initramfs
93         fi
94
95         # Partition the usb drive. The partition listed first can be read by linux
96         # and windows operating systems.  It is located at the 'end' of the drive
97         # The partition listed second contains the operating system and boot loader,
98         # it is located at the 'beginning' of the drive. The partition listed last fills
99         # the space between the other two, and is used to record changes made to the 
100         # operating system
101         sfdisk "${usb_drive}" <<- EOF
102
103         label: gpt
104
105         start=$usbdata_part_start, type=11
106         start=2048, size=$live_part_size, type=1
107         type=20
108         EOF
109
110         # waiting to ensure disk has been re recognised after partitioning
111         sleep 10
112
113         # Format each partition with the relevant filesystem.
114         mkfs.ntfs --fast -L usbdata "${usb_drive}1"
115         mkfs.fat -F 32 "${usb_drive}2"
116         mkfs.ext4 -q -F -L casper-rw "${usb_drive}3"
117
118         # Create a temporary directory
119         m_point=$(mktemp -d)
120
121         # Mount the drive to the temporary directory, create some folders/directories,
122         # copy the os image, and install the boot loader.
123         mount "${usb_drive}2" "${m_point}"
124         mkdir "${m_point}"/{boot,iso_boot}
125         cp "${os_image}" "${m_point}/iso_boot" && sync
126         grub-install "${usb_drive}" \
127                 --target=x86_64-efi \
128                 --efi-directory="${m_point}" \
129                 --boot-directory="${m_point}/boot" \
130                 --removable
131
132         # Install the configuration file for the bootloader
133         cat <<-EOF> "${m_point}/boot/grub/grub.cfg"
134         set timeout=10
135         set default=0
136         insmod loopback
137         insmod all_video
138
139         menuentry "Run ${os_name} Persistent, in RAM" {
140                 loopback loop /iso_boot/${image_name}
141                 set gfxpayload=keep
142                 linux (loop)/${kernel} boot=casper iso-scan/filename=/iso_boot/${image_name} quiet splash persistent toram ---
143                 initrd (loop)/${initramfs}
144         }
145
146         menuentry "Run ${os_name} - Persistent" {
147                 loopback loop /iso_boot/${image_name}
148                 set gfxpayload=keep
149                 linux (loop)/${kernel} boot=casper iso-scan/filename=/iso_boot/${image_name} quiet splash persistent ---
150                 initrd (loop)/${initramfs}
151         }
152
153         menuentry "Run ${os_name}" {
154                 loopback loop /iso_boot/${image_name}
155                 set gfxpayload=keep
156                 linux (loop)/${kernel} boot=casper iso-scan/filename=/iso_boot/${image_name} quiet splash ---
157                 initrd (loop)/${initramfs}
158         }
159         EOF
160
161         # Clean up
162         umount "${m_point}"
163         rmdir "${m_point}"
164 }
165
166 main 2> >(sed $'s,.*,\e[31m&\e[m, '>&2)