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