1 /* partition 1.13 - Make a partition table Author: Kees J. Bot 2 * 27 Apr 1992 3 */ 4 #define nil ((void*)0) 5 #include <stdio.h> 6 #include <sys/types.h> 7 #include <stdlib.h> 8 #include <unistd.h> 9 #include <fcntl.h> 10 #include <sys/stat.h> 11 #include <string.h> 12 #include <errno.h> 13 #include <sys/ioctl.h> 14 #include <limits.h> 15 #include <stdint.h> 16 #include <assert.h> 17 18 #ifdef __minix 19 #include <machine/partition.h> 20 #include <minix/config.h> 21 #include <minix/const.h> 22 #include <minix/partition.h> 23 #else 24 #include "partition.h" 25 #define NR_PARTITIONS 4 26 #endif 27 28 #define SECTOR_SIZE 512 29 30 #define arraysize(a) (sizeof(a)/sizeof((a)[0])) 31 #define arraylimit(a) ((a) + arraysize(a)) 32 33 char *arg0; 34 35 void report(const char *label) 36 { 37 fprintf(stderr, "%s: %s: %s\n", arg0, label, strerror(errno)); 38 } 39 40 void fatal(const char *label) 41 { 42 report(label); 43 exit(1); 44 } 45 46 int aflag; /* Add a new partition to the current table. */ 47 int mflag; /* Minix rules, no need for alignment. */ 48 int rflag; /* Report current partitions. */ 49 int fflag; /* Force making a table even if too small. */ 50 int nflag; /* Play-act, don't really do it. */ 51 52 int cylinders, heads, sectors; /* Device's geometry */ 53 int pad; /* Partitions must be padded. */ 54 55 /* Descriptions of the device to divide and the partitions to make, including 56 * gaps between partitions. 57 */ 58 char *device; 59 struct part_entry primary, table[2 * NR_PARTITIONS + 1]; 60 int npart; 61 62 /* Extra flags at construction time. */ 63 #define EXPAND_FLAG 0x01 /* Add the remaining sectors to this one */ 64 #define EXIST_FLAG 0x02 /* Use existing partition */ 65 66 void find_exist(struct part_entry *exist, int sysind, int nr) 67 { 68 int f; 69 uint16_t signature; 70 struct part_entry oldtable[NR_PARTITIONS]; 71 int n, i; 72 uint32_t minlow, curlow; 73 struct part_entry *cur; 74 char *nr_s[] = { "", "second ", "third ", "fourth" }; 75 76 if ((f= open(device, O_RDONLY)) < 0 77 78 || lseek(f, (off_t) PART_TABLE_OFF, SEEK_SET) == -1 79 80 || read(f, oldtable, sizeof(oldtable)) < 0 81 82 || read(f, &signature, sizeof(signature)) < 0 83 84 || close(f) < 0 85 ) fatal(device); 86 87 minlow= 0; 88 n= 0; 89 for (;;) { 90 curlow= -1; 91 cur= nil; 92 for (i= 0; i < NR_PARTITIONS; i++) { 93 if (signature == 0xAA55 94 && oldtable[i].sysind != NO_PART 95 && oldtable[i].lowsec >= minlow 96 && oldtable[i].lowsec < curlow 97 ) { 98 cur= &oldtable[i]; 99 curlow= oldtable[i].lowsec; 100 } 101 } 102 if (n == nr) break; 103 n++; 104 minlow= curlow+1; 105 } 106 107 if (cur == nil || cur->sysind != sysind) { 108 fprintf(stderr, 109 "%s: Can't find a %sexisting partition of type 0x%02X\n", 110 arg0, nr_s[nr], sysind); 111 exit(1); 112 } 113 *exist = *cur; 114 } 115 116 void write_table(void) 117 { 118 int f; 119 uint16_t signature= 0xAA55; 120 struct part_entry newtable[NR_PARTITIONS]; 121 int i; 122 123 if (nflag) { 124 printf("(Table not written)\n"); 125 return; 126 } 127 128 for (i= 0; i < NR_PARTITIONS; i++) newtable[i]= table[1 + 2*i]; 129 130 /* we have a abstract struct but it must conform to a certain 131 * reality that will never change (in-MBR sizes and offsets). 132 * each partition entry is 16 bytes and there are 4 of them. 133 * this also determines the signature offset. 134 */ 135 assert(sizeof(struct part_entry) == 16); 136 assert(sizeof(newtable) == 64); 137 138 if ((f= open(device, O_WRONLY)) < 0 139 140 || lseek(f, (off_t) PART_TABLE_OFF, SEEK_SET) == -1 141 142 || write(f, newtable, sizeof(newtable)) < 0 143 144 || write(f, &signature, sizeof(signature)) < 0 145 146 || close(f) < 0 147 ) fatal(device); 148 } 149 150 void sec2dos(unsigned long sec, unsigned char *dos) 151 /* Translate a sector number into the three bytes DOS uses. */ 152 { 153 unsigned secspcyl= heads * sectors; 154 unsigned cyl; 155 156 cyl= sec / secspcyl; 157 dos[2]= cyl; 158 dos[1]= ((sec % sectors) + 1) | ((cyl >> 2) & 0xC0); 159 dos[0]= (sec % secspcyl) / sectors; 160 } 161 162 void show_chs(unsigned long pos) 163 { 164 int cyl, head, sec; 165 166 if (pos == -1) { 167 cyl= head= 0; 168 sec= -1; 169 } else { 170 cyl= pos / (heads * sectors); 171 head= (pos / sectors) - (cyl * heads); 172 sec= pos % sectors; 173 } 174 printf(" %4d/%03d/%02d", cyl, head, sec); 175 } 176 177 void show_part(struct part_entry *p) 178 { 179 static int banner= 0; 180 int n; 181 182 n= p - table; 183 if ((n % 2) == 0) return; 184 185 if (!banner) { 186 printf( 187 "Part First Last Base Size Kb\n"); 188 banner= 1; 189 } 190 191 printf("%3d ", (n-1) / 2); 192 show_chs(p->lowsec); 193 show_chs(p->lowsec + p->size - 1); 194 printf(" %8lu %8lu %7lu\n", p->lowsec, p->size, p->size / 2); 195 } 196 197 void usage(void) 198 { 199 fprintf(stderr, 200 "Usage: partition [-mfn] device [type:]length[+*] ...\n"); 201 exit(1); 202 } 203 204 #define between(a, c, z) ((unsigned) ((c) - (a)) <= ((z) - (a))) 205 206 void parse(char *descr) 207 { 208 int seen= 0, sysind, flags, c; 209 unsigned long lowsec, size; 210 211 lowsec= 0; 212 213 if (strchr(descr, ':') == nil) { 214 /* A hole. */ 215 if ((npart % 2) != 0) { 216 fprintf(stderr, "%s: Two holes can't be adjacent.\n", 217 arg0); 218 exit(1); 219 } 220 sysind= NO_PART; 221 seen|= 1; 222 } else { 223 /* A partition. */ 224 if ((npart % 2) == 0) { 225 /* Need a hole before this partition. */ 226 if (npart == 0) { 227 /* First hole contains the partition table. */ 228 table[0].size= 1; 229 } 230 npart++; 231 } 232 sysind= 0; 233 for (;;) { 234 c= *descr++; 235 if (between('0', c, '9')) 236 c= (c - '0') + 0x0; 237 else 238 if (between('a', c, 'z')) 239 c= (c - 'a') + 0xa; 240 else 241 if (between('A', c, 'Z')) 242 c= (c - 'A') + 0xA; 243 else 244 break; 245 sysind= 0x10 * sysind + c; 246 seen|= 1; 247 } 248 if (c != ':') usage(); 249 } 250 251 flags= 0; 252 253 if (strncmp(descr, "exist", 5) == 0 && (npart % 2) == 1) { 254 struct part_entry exist; 255 256 find_exist(&exist, sysind, (npart - 1) / 2); 257 sysind= exist.sysind; 258 lowsec= exist.lowsec; 259 size= exist.size; 260 flags |= EXIST_FLAG; 261 descr += 5; 262 c= *descr++; 263 seen|= 2; 264 } else { 265 size= 0; 266 while (between('0', (c= *descr++), '9')) { 267 size= 10 * size + (c - '0'); 268 seen|= 2; 269 } 270 } 271 272 for (;;) { 273 if (c == '*') 274 flags|= ACTIVE_FLAG; 275 else 276 if (c == '+' && !(flags & EXIST_FLAG)) 277 flags|= EXPAND_FLAG; 278 else 279 break; 280 c= *descr++; 281 } 282 283 if (seen != 3 || c != 0) usage(); 284 285 if (npart == arraysize(table)) { 286 fprintf(stderr, "%s: too many partitions, only %d possible.\n", 287 arg0, NR_PARTITIONS); 288 exit(1); 289 } 290 table[npart].bootind= flags; 291 table[npart].sysind= sysind; 292 table[npart].lowsec= lowsec; 293 table[npart].size= size; 294 npart++; 295 } 296 297 void geometry(void) 298 /* Get the geometry of the drive the device lives on, and the base and size 299 * of the device. 300 */ 301 { 302 int fd; 303 struct stat sb; 304 305 if ((fd= open(device, O_RDONLY)) < 0) fatal(device); 306 307 #ifdef __minix 308 struct part_geom geometry; 309 310 311 /* Get the geometry of the drive, and the device's base and size. */ 312 if (ioctl(fd, DIOCGETP, &geometry) < 0) 313 { 314 /* Use the same fake geometry as part. */ 315 if (fstat(fd, &sb) < 0) 316 fatal(device); 317 geometry.base= ((u64_t)(0)); 318 geometry.size= ((u64_t)(sb.st_size)); 319 geometry.sectors= 32; 320 geometry.heads= 64; 321 geometry.cylinders= (sb.st_size-1)/SECTOR_SIZE/ 322 (geometry.sectors*geometry.heads) + 1; 323 } 324 primary.lowsec= (unsigned long)(geometry.base / SECTOR_SIZE); 325 primary.size = (unsigned long)(geometry.size / SECTOR_SIZE); 326 cylinders= geometry.cylinders; 327 heads= geometry.heads; 328 sectors= geometry.sectors; 329 #else 330 if (fstat(fd, &sb) < 0) fatal(device); 331 primary.lowsec= 0; 332 primary.size= sb.st_size / SECTOR_SIZE; 333 heads= 64; 334 sectors= 32; 335 cylinders= (sb.st_size-1) / SECTOR_SIZE / (sectors*heads) + 1; 336 #endif 337 338 close(fd); 339 340 /* Is this a primary partition table? If so then pad partitions. */ 341 pad= (!mflag && primary.lowsec == 0); 342 } 343 344 void boundary(struct part_entry *pe, int exp) 345 /* Expand or reduce a primary partition to a track or cylinder boundary to 346 * avoid giving the fdisk's of simpler operating systems a fit. 347 */ 348 { 349 unsigned n; 350 351 n= !pad ? 1 : pe == &table[0] ? sectors : heads * sectors; 352 if (exp) pe->size+= n - 1; 353 pe->size= ((pe->lowsec + pe->size) / n * n) - pe->lowsec; 354 } 355 356 void distribute(void) 357 /* Fit the partitions onto the device. Try to start and end them on a 358 * cylinder boundary if so required. The first partition is to start on 359 * track 1, not on cylinder 1. 360 */ 361 { 362 struct part_entry *pe, *exp; 363 long count; 364 unsigned long base, oldbase; 365 366 do { 367 exp= nil; 368 base= primary.lowsec; 369 count= primary.size; 370 371 for (pe= table; pe < arraylimit(table); pe++) { 372 oldbase= base; 373 if (pe->bootind & EXIST_FLAG) { 374 if (base > pe->lowsec) { 375 fprintf(stderr, 376 "%s: fixed partition %ld is preceded by too big partitions/holes\n", 377 arg0, ((pe - table) - 1) / 2); 378 exit(1); 379 } 380 exp= nil; /* XXX - Extend before? */ 381 } else { 382 pe->lowsec= base; 383 boundary(pe, 1); 384 if (pe->bootind & EXPAND_FLAG) exp= pe; 385 } 386 base= pe->lowsec + pe->size; 387 count-= base - oldbase; 388 } 389 if (count < 0) { 390 if (fflag) break; 391 fprintf(stderr, "%s: %s is %ld sectors too small\n", 392 arg0, device, -count); 393 exit(1); 394 } 395 if (exp != nil) { 396 /* Add leftover space to the partition marked for 397 * expanding. 398 */ 399 exp->size+= count; 400 boundary(exp, 0); 401 exp->bootind&= ~EXPAND_FLAG; 402 } 403 } while (exp != nil); 404 405 for (pe= table; pe < arraylimit(table); pe++) { 406 if (pe->sysind == NO_PART) { 407 memset(pe, 0, sizeof(*pe)); 408 } else { 409 sec2dos(pe->lowsec, &pe->start_head); 410 sec2dos(pe->lowsec + pe->size - 1, &pe->last_head); 411 pe->bootind&= ACTIVE_FLAG; 412 } 413 show_part(pe); 414 } 415 } 416 417 int main(int argc, char **argv) 418 { 419 int i; 420 421 if ((arg0= strrchr(argv[0], '/')) == nil) arg0= argv[0]; else arg0++; 422 423 i= 1; 424 while (i < argc && argv[i][0] == '-') { 425 char *opt= argv[i++] + 1; 426 427 if (opt[0] == '-' && opt[1] == 0) break; 428 429 while (*opt != 0) switch (*opt++) { 430 case 'a': aflag= 1; break; 431 case 'm': mflag= 1; break; 432 case 'r': rflag= 1; break; 433 case 'f': fflag= 1; break; 434 case 'n': nflag= 1; break; 435 default: usage(); 436 } 437 } 438 439 if (rflag) { 440 if (aflag) usage(); 441 if ((argc - i) != 1) usage(); 442 fprintf(stderr, "%s: -r is not yet implemented\n", __func__); 443 exit(1); 444 } else { 445 if ((argc - i) < 1) usage(); 446 if (aflag) fprintf(stderr, "%s: -a is not yet implemented\n", __func__); 447 448 device= argv[i++]; 449 geometry(); 450 451 while (i < argc) parse(argv[i++]); 452 453 distribute(); 454 write_table(); 455 } 456 exit(0); 457 } 458