1 #!/bin/sh 2 3 # Emit a partition table for a device employing parameters such as the start, 4 # size, and type. 5 # 6 # Copyright (C) 2019 Paul Boddie <paul@boddie.org.uk> 7 # 8 # This program is free software; you can redistribute it and/or modify it under 9 # the terms of the GNU General Public License as published by the Free Software 10 # Foundation; either version 3 of the License, or (at your option) any later 11 # version. 12 # 13 # This program is distributed in the hope that it will be useful, but WITHOUT 14 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 16 # details. 17 # 18 # You should have received a copy of the GNU General Public License along with 19 # this program. If not, see <http://www.gnu.org/licenses/>. 20 21 PROGNAME=`basename "$0"` 22 THISDIR=`dirname "$0"` 23 24 COMMON="$THISDIR/makesd-common" 25 SFDISK="/sbin/sfdisk" 26 27 . "$COMMON" 28 29 30 31 # Cylinder size in sectors for alignment purposes. 32 33 HEADS=255 34 SECTORS=63 35 CYLINDER_SIZE=$(($HEADS * $SECTORS)) 36 37 # Global partition number and previous partition details. 38 39 PARTNUM=1 40 PREVSTART= 41 PREVSIZE= 42 PREVTYPE= 43 44 # Emit any previous partition details as a complete sfdisk-compatible record. 45 46 emit_partition() 47 { 48 if [ "$PREVSTART" ] || [ "$PREVSIZE" ] || [ "$PREVTYPE" ] ; then 49 echo -n "$PARTNUM : " 50 emit_partition_fields | sed 's/^ //;s/ /,/g' 51 PARTNUM=$(($PARTNUM + 1)) 52 fi 53 } 54 55 # Emit the previous partition fields. 56 57 emit_partition_fields() 58 { 59 echo -n " start=${PREVSTART}${SFDISK_UNIT_SUFFIX}" 60 61 REMAINING=$(($DEVSIZE - $PREVSTART)) 62 63 # Retain any previously calculated size. 64 # Without a size, use start details to calculate a size. 65 # Without start details, claim the rest of the device. 66 67 if [ "$PREVSIZE" ] ; then 68 : 69 elif [ "$START" ] ; then 70 PREVSIZE=$((`align_cylinder $START` - $PREVSTART)) 71 else 72 PREVSIZE=$REMAINING 73 fi 74 75 if [ "$PREVSIZE" -gt "$REMAINING" ] ; then 76 PREVSIZE=$REMAINING 77 fi 78 79 echo -n " size=${PREVSIZE}${SFDISK_UNIT_SUFFIX}" 80 81 if [ "$PREVTYPE" ] ; then 82 echo -n " Id=`partition_type $PREVTYPE`" 83 fi 84 85 echo 86 } 87 88 # Retain the current partition details. 89 90 store_partition() 91 { 92 # Define the partition start using a specified position. 93 # Alternatively, use previous start and size information. 94 # Otherwise, the first partition is being defined. 95 96 if [ "$START" ] && [ "$START" != '-' ] ; then 97 PREVSTART=`align_cylinder $START` 98 elif [ "$PREVSTART" ] && [ "$PREVSIZE" ] ; then 99 PREVSTART=`align_cylinder $(($PREVSTART + $PREVSIZE))` 100 else 101 PREVSTART=0 102 fi 103 104 # Ensure that the first partition starts at sector one. 105 106 if [ "$PREVSTART" = '0' ] ; then 107 PREVSTART=1 108 fi 109 110 # Calculate and align the stated size. 111 # Otherwise, defer the calculation until emitting the details. 112 113 if [ "$SIZE" ] && [ "$SIZE" != '-' ] ; then 114 PREVSIZE=$(($SIZE * $DEVSIZE / 100)) 115 PREVSIZE=`align_cylinder $PREVSIZE` 116 117 if [ "$PREVSTART" = '1' ] ; then 118 PREVSIZE=$(($PREVSIZE - 1)) 119 fi 120 else 121 PREVSIZE= 122 fi 123 124 PREVTYPE=$TYPE 125 } 126 127 # Emit the current partition details and proceed to the next partition. 128 129 next_partition() 130 { 131 emit_partition 132 store_partition 133 } 134 135 # Convert the partition type to an sdisk-compatible identifier. 136 137 partition_type() 138 { 139 case "$1" in 140 ( ext* ) echo "0x83" ;; 141 ( swap ) echo "0x82" ;; 142 ( fat ) echo "0x0c" ;; 143 ( * ) echo "0x83" ;; 144 esac 145 } 146 147 148 149 # device_size <device> 150 # 151 # Obtain the size of the given disk or partition in 1024-byte blocks. 152 153 device_size() 154 { 155 "$SFDISK" -s "$1" 156 } 157 158 # Align to cylinders. 159 160 align_cylinder() 161 { 162 if [ ! "$ALIGN_CYLINDER" ] ; then 163 echo $1 164 return 165 fi 166 167 # Round up to the nearest cylinder. 168 169 CYLINDER=$((($1 + $CYLINDER_SIZE - 1) / $CYLINDER_SIZE)) 170 171 # Emit the number of sectors. 172 173 echo $(($CYLINDER * $CYLINDER_SIZE)) 174 } 175 176 # Test sfdisk behaviour and obtain useful information. 177 178 init_sfdisk() 179 { 180 SFDISK_UNIT_SUFFIX= 181 182 # Obtain the device size in 512-byte sectors. 183 184 DEVSIZE=$((`device_size "$1"` * 2)) 185 186 # Find the cylinder-addressable size. 187 188 if [ "$ALIGN_CYLINDER" ] ; then 189 CYLINDERS=$(($DEVSIZE / $CYLINDER_SIZE)) 190 DEVSIZE=$(($CYLINDERS * $CYLINDER_SIZE)) 191 fi 192 } 193 194 195 196 # Emit the help message if requested. 197 198 if [ "$1" = '--help' ] ; then 199 cat 1>&2 <<EOF 200 Usage: $PROGNAME [ --align ] 201 202 Produce partition descriptions, indicating partition type, start position and 203 size for each partition. 204 205 The input for this program is supplied via standard input as a partitioning 206 summary with each line providing a collection of tab-separated values. These 207 values appear in the following order: 208 209 <start> <size> <type> 210 211 Start positions are indicated as numbers of 512-byte sectors. 212 213 Sizes are indicated as percentages of the entire device; if omitted, the 214 remainder of the device will be used. 215 216 Types recognised include ext, ext2, ext3, ext4, fat and swap. Other types are 217 interpreted as Linux partitions. 218 219 $(align_cylinder_description) 220 EOF 221 exit 0 222 fi 223 224 # Test for the cylinder alignment option. 225 226 if test_align_cylinder $* ; then shift 1 ; fi 227 228 # Obtain details of the selected device. 229 230 check_device 231 232 # Initialise sfdisk usage. 233 234 init_sfdisk "$DEV" 235 236 while read_fields ; do 237 next_partition 238 done 239 240 # Emit the last partition. 241 242 emit_partition