1 /* 2 * Copyright (c) 1983, 1988, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #include <sys/cdefs.h> 35 #ifndef lint 36 __COPYRIGHT("@(#) Copyright (c) 1983, 1988, 1993\n\ 37 The Regents of the University of California. All rights reserved.\n"); 38 #endif /* not lint */ 39 40 #ifndef lint 41 #if 0 42 static char sccsid[] = "from: @(#)diskpart.c 8.3 (Berkeley) 11/30/94"; 43 #else 44 __RCSID("$NetBSD: diskpart.c,v 1.9 1997/10/17 00:16:55 lukem Exp $"); 45 #endif 46 #endif /* not lint */ 47 48 /* 49 * Program to calculate standard disk partition sizes. 50 */ 51 #include <sys/param.h> 52 #define DKTYPENAMES 53 #include <sys/disklabel.h> 54 55 #include <ctype.h> 56 #include <limits.h> 57 #include <stdio.h> 58 #include <stdlib.h> 59 #include <string.h> 60 #include <unistd.h> 61 62 #define for_now /* show all of `c' partition for disklabel */ 63 #define NPARTITIONS 8 64 #define PART(x) (x - 'a') 65 66 /* 67 * Default partition sizes, where they exist. 68 */ 69 #define NDEFAULTS 4 70 int defpart[NDEFAULTS][NPARTITIONS] = { 71 { 15884, 66880, 0, 15884, 307200, 0, 0, 291346 }, /* ~ 356+ Mbytes */ 72 { 15884, 33440, 0, 15884, 55936, 0, 0, 291346 }, /* ~ 206-355 Mbytes */ 73 { 15884, 33440, 0, 15884, 55936, 0, 0, 0 }, /* ~ 61-205 Mbytes */ 74 { 15884, 10032, 0, 15884, 0, 0, 0, 0 }, /* ~ 20-60 Mbytes */ 75 }; 76 77 /* 78 * Each array defines a layout for a disk; 79 * that is, the collection of partitions totally 80 * covers the physical space on a disk. 81 */ 82 #define NLAYOUTS 3 83 char layouts[NLAYOUTS][NPARTITIONS] = { 84 { 'a', 'b', 'h', 'g' }, 85 { 'a', 'b', 'h', 'd', 'e', 'f' }, 86 { 'c' }, 87 }; 88 89 /* 90 * Default disk block and disk block fragment 91 * sizes for each file system. Those file systems 92 * with zero block and frag sizes are special cases 93 * (e.g. swap areas or for access to the entire device). 94 */ 95 struct partition defparam[NPARTITIONS] = { 96 { 0, 0, 1024, FS_UNUSED, 8, { 0 }, }, /* a */ 97 { 0, 0, 1024, FS_SWAP, 8, { 0 }, }, /* b */ 98 { 0, 0, 1024, FS_UNUSED, 8, { 0 }, }, /* c */ 99 { 0, 0, 512, FS_UNUSED, 8, { 0 }, }, /* d */ 100 { 0, 0, 1024, FS_UNUSED, 8, { 0 }, }, /* e */ 101 { 0, 0, 1024, FS_UNUSED, 8, { 0 }, }, /* f */ 102 { 0, 0, 1024, FS_UNUSED, 8, { 0 }, }, /* g */ 103 { 0, 0, 1024, FS_UNUSED, 8, { 0 }, } /* h */ 104 }; 105 106 /* 107 * Each disk has some space reserved for a bad sector 108 * forwarding table. DEC standard 144 uses the first 109 * 5 even numbered sectors in the last track of the 110 * last cylinder for replicated storage of the bad sector 111 * table; another 126 sectors past this is needed as a 112 * pool of replacement sectors. 113 */ 114 int badsecttable = 126; /* # sectors */ 115 116 int pflag; /* print device driver partition tables */ 117 int dflag; /* print disktab entry */ 118 119 int gettype __P((const char *, char **)); 120 int main __P((int, char **)); 121 struct disklabel *promptfordisk __P((const char *)); 122 void usage __P((void)); 123 124 int 125 main(argc, argv) 126 int argc; 127 char *argv[]; 128 { 129 130 struct disklabel *dp; 131 int curcyl, spc, def, part, layout, j, ch; 132 int threshhold, numcyls[NPARTITIONS], startcyl[NPARTITIONS]; 133 off_t totsize = 0; 134 char *lp, *tyname; 135 136 while ((ch = getopt(argc, argv, "pds:")) != -1) { 137 switch (ch) { 138 case 'd': 139 dflag++; 140 break; 141 142 case 'p': 143 pflag++; 144 break; 145 146 case 's': 147 totsize = strtoul(optarg, &lp, 10); 148 if (*lp != '\0') 149 usage(); 150 break; 151 152 case '?': 153 default: 154 usage(); 155 /* NOTREACHED */ 156 } 157 } 158 argc -= optind; 159 argv += optind; 160 161 if (argc != 1) { 162 usage(); 163 /* NOTREACHED */ 164 } 165 166 dp = getdiskbyname(*argv); 167 if (dp == NULL) { 168 if (isatty(0)) 169 dp = promptfordisk(*argv); 170 if (dp == NULL) { 171 fprintf(stderr, "%s: unknown disk type\n", *argv); 172 exit(1); 173 } 174 } 175 if (dp->d_flags & D_REMOVABLE) 176 tyname = "removable"; 177 else if (dp->d_flags & D_RAMDISK) 178 tyname = "simulated"; 179 else 180 tyname = "winchester"; 181 spc = dp->d_secpercyl; 182 /* 183 * Bad sector table contains one track for the replicated 184 * copies of the table and enough full tracks preceding 185 * the last track to hold the pool of free blocks to which 186 * bad sectors are mapped. 187 * If disk size was specified explicitly, use specified size. 188 */ 189 if (dp->d_type == DTYPE_SMD && dp->d_flags & D_BADSECT && 190 totsize == 0) { 191 badsecttable = dp->d_nsectors + 192 roundup(badsecttable, dp->d_nsectors); 193 threshhold = howmany(spc, badsecttable); 194 } else { 195 badsecttable = 0; 196 threshhold = 0; 197 } 198 /* 199 * If disk size was specified, recompute number of cylinders 200 * that may be used, and set badsecttable to any remaining 201 * fraction of the last cylinder. 202 */ 203 if (totsize != 0) { 204 dp->d_ncylinders = howmany(totsize, spc); 205 badsecttable = spc * dp->d_ncylinders - totsize; 206 } 207 208 /* 209 * Figure out if disk is large enough for 210 * expanded swap area and 'd', 'e', and 'f' 211 * partitions. Otherwise, use smaller defaults 212 * based on RK07. 213 */ 214 for (def = 0; def < NDEFAULTS; def++) { 215 curcyl = 0; 216 for (part = PART('a'); part < NPARTITIONS; part++) 217 curcyl += howmany(defpart[def][part], spc); 218 if (curcyl < dp->d_ncylinders - threshhold) 219 break; 220 } 221 if (def >= NDEFAULTS) { 222 fprintf(stderr, "%s: disk too small, calculate by hand\n", 223 *argv); 224 exit(1); 225 } 226 227 /* 228 * Calculate number of cylinders allocated to each disk 229 * partition. We may waste a bit of space here, but it's 230 * in the interest of (very backward) compatibility 231 * (for mixed disk systems). 232 */ 233 for (curcyl = 0, part = PART('a'); part < NPARTITIONS; part++) { 234 numcyls[part] = 0; 235 if (defpart[def][part] != 0) { 236 numcyls[part] = howmany(defpart[def][part], spc); 237 curcyl += numcyls[part]; 238 } 239 } 240 numcyls[PART('f')] = dp->d_ncylinders - curcyl; 241 numcyls[PART('g')] = 242 numcyls[PART('d')] + numcyls[PART('e')] + numcyls[PART('f')]; 243 numcyls[PART('c')] = dp->d_ncylinders; 244 defpart[def][PART('f')] = numcyls[PART('f')] * spc - badsecttable; 245 defpart[def][PART('g')] = numcyls[PART('g')] * spc - badsecttable; 246 defpart[def][PART('c')] = numcyls[PART('c')] * spc; 247 #ifndef for_now 248 if (totsize || !pflag) 249 #else 250 if (totsize) 251 #endif 252 defpart[def][PART('c')] -= badsecttable; 253 254 /* 255 * Calculate starting cylinder number for each partition. 256 * Note the 'h' partition is physically located before the 257 * 'g' or 'd' partition. This is reflected in the layout 258 * arrays defined above. 259 */ 260 for (layout = 0; layout < NLAYOUTS; layout++) { 261 curcyl = 0; 262 for (lp = layouts[layout]; *lp != 0; lp++) { 263 startcyl[PART(*lp)] = curcyl; 264 curcyl += numcyls[PART(*lp)]; 265 } 266 } 267 268 if (pflag) { 269 printf("}, %s_sizes[%d] = {\n", dp->d_typename, NPARTITIONS); 270 for (part = PART('a'); part < NPARTITIONS; part++) { 271 if (numcyls[part] == 0) { 272 printf("\t0,\t0,\n"); 273 continue; 274 } 275 if (dp->d_type != DTYPE_MSCP) { 276 printf("\t%d,\t%d,\t\t/* %c=cyl %d thru %d */\n", 277 defpart[def][part], startcyl[part], 278 'A' + part, startcyl[part], 279 startcyl[part] + numcyls[part] - 1); 280 continue; 281 } 282 printf("\t%d,\t%d,\t\t/* %c=sectors %d thru %d */\n", 283 defpart[def][part], spc * startcyl[part], 284 'A' + part, spc * startcyl[part], 285 spc * startcyl[part] + defpart[def][part] - 1); 286 } 287 exit(0); 288 } 289 if (dflag) { 290 int nparts; 291 292 /* 293 * In case the disk is in the ``in-between'' range 294 * where the 'g' partition is smaller than the 'h' 295 * partition, reverse the frag sizes so the /usr partition 296 * is always set up with a frag size larger than the 297 * user's partition. 298 */ 299 if (defpart[def][PART('g')] < defpart[def][PART('h')]) { 300 int temp; 301 302 temp = defparam[PART('h')].p_fsize; 303 defparam[PART('h')].p_fsize = 304 defparam[PART('g')].p_fsize; 305 defparam[PART('g')].p_fsize = temp; 306 } 307 printf("%s:\\\n", dp->d_typename); 308 printf("\t:ty=%s:ns#%d:nt#%d:nc#%d:", tyname, 309 dp->d_nsectors, dp->d_ntracks, dp->d_ncylinders); 310 if (dp->d_secpercyl != dp->d_nsectors * dp->d_ntracks) 311 printf("sc#%d:", dp->d_secpercyl); 312 if (dp->d_type == DTYPE_SMD && dp->d_flags & D_BADSECT) 313 printf("sf:"); 314 printf("\\\n\t:dt=%s:", dktypenames[dp->d_type]); 315 for (part = NDDATA - 1; part >= 0; part--) 316 if (dp->d_drivedata[part]) 317 break; 318 for (j = 0; j <= part; j++) 319 printf("d%d#%d:", j, dp->d_drivedata[j]); 320 printf("\\\n"); 321 for (nparts = 0, part = PART('a'); part < NPARTITIONS; part++) 322 if (defpart[def][part] != 0) 323 nparts++; 324 for (part = PART('a'); part < NPARTITIONS; part++) { 325 if (defpart[def][part] == 0) 326 continue; 327 printf("\t:p%c#%d:", 'a' + part, defpart[def][part]); 328 printf("o%c#%d:b%c#%d:f%c#%d:", 329 'a' + part, spc * startcyl[part], 330 'a' + part, 331 defparam[part].p_frag * defparam[part].p_fsize, 332 'a' + part, defparam[part].p_fsize); 333 if (defparam[part].p_fstype == FS_SWAP) 334 printf("t%c=swap:", 'a' + part); 335 nparts--; 336 printf("%s\n", nparts > 0 ? "\\" : ""); 337 } 338 #ifdef for_now 339 defpart[def][PART('c')] -= badsecttable; 340 part = PART('c'); 341 printf("#\t:p%c#%d:", 'a' + part, defpart[def][part]); 342 printf("o%c#%d:b%c#%d:f%c#%d:\n", 343 'a' + part, spc * startcyl[part], 344 'a' + part, 345 defparam[part].p_frag * defparam[part].p_fsize, 346 'a' + part, defparam[part].p_fsize); 347 #endif 348 exit(0); 349 } 350 printf("%s: #sectors/track=%d, #tracks/cylinder=%d #cylinders=%d\n", 351 dp->d_typename, dp->d_nsectors, dp->d_ntracks, 352 dp->d_ncylinders); 353 printf("\n Partition\t Size\t Offset\t Range\n"); 354 for (part = PART('a'); part < NPARTITIONS; part++) { 355 printf("\t%c\t", 'a' + part); 356 if (numcyls[part] == 0) { 357 printf(" unused\n"); 358 continue; 359 } 360 printf("%7d\t%7d\t%4d - %d%s\n", 361 defpart[def][part], startcyl[part] * spc, 362 startcyl[part], startcyl[part] + numcyls[part] - 1, 363 defpart[def][part] % spc ? "*" : ""); 364 } 365 exit(0); 366 } 367 368 struct disklabel disk; 369 370 struct field { 371 char *f_name; 372 char *f_defaults; 373 u_int32_t *f_location; 374 } fields[] = { 375 { "sector size", "512", &disk.d_secsize }, 376 { "#sectors/track", 0, &disk.d_nsectors }, 377 { "#tracks/cylinder", 0, &disk.d_ntracks }, 378 { "#cylinders", 0, &disk.d_ncylinders }, 379 { 0, 0, 0 }, 380 }; 381 382 struct disklabel * 383 promptfordisk(name) 384 const char *name; 385 { 386 struct disklabel *dp = &disk; 387 struct field *fp; 388 int i; 389 char buf[BUFSIZ], **tp, *cp; 390 391 strncpy(dp->d_typename, name, sizeof(dp->d_typename)); 392 fprintf(stderr, 393 "%s: unknown disk type, want to supply parameters (y/n)? ", 394 name); 395 if ((fgets(buf, BUFSIZ, stdin) == NULL) || buf[0] != 'y') 396 return ((struct disklabel *)0); 397 for (;;) { 398 fprintf(stderr, "Disk/controller type (%s)? ", dktypenames[1]); 399 if (fgets(buf, BUFSIZ, stdin) == NULL) 400 return ((struct disklabel *)0); 401 if ((cp = strchr(buf, '\n')) != NULL) 402 *cp = '\0'; 403 if (buf[0] == '\0') { 404 dp->d_type = 1; 405 break; 406 } 407 if ((i = gettype(buf, dktypenames)) >= 0) { 408 dp->d_type = i; 409 break; 410 } 411 fprintf(stderr, "%s: unrecognized controller type\n", buf); 412 fprintf(stderr, "use one of:\n"); 413 for (tp = dktypenames; *tp; tp++) 414 if (strchr(*tp, ' ') == 0) 415 fprintf(stderr, "\t%s\n", *tp); 416 } 417 gettype: 418 dp->d_flags = 0; 419 fprintf(stderr, "type (winchester|removable|simulated)? "); 420 if (fgets(buf, BUFSIZ, stdin) == NULL) 421 return ((struct disklabel *)0); 422 if ((cp = strchr(buf, '\n')) != NULL) 423 *cp = '\0'; 424 if (buf[0] == '\0') 425 goto gettype; 426 switch (buf[0]) { 427 case 'r': 428 dp->d_flags = D_REMOVABLE; 429 break; 430 case 's': 431 dp->d_flags = D_RAMDISK; 432 break; 433 case 'w': 434 break; 435 default: 436 fprintf(stderr, "%s: bad disk type\n", buf); 437 /* FALLTHROUGH */ 438 case '\0': 439 goto gettype; 440 } 441 fprintf(stderr, "(type <cr> to get default value, if only one)\n"); 442 if (dp->d_type == DTYPE_SMD) { 443 fprintf(stderr, 444 "Do '%s' disks support bad144 bad block forwarding (yes)? ", 445 dp->d_typename); 446 if (fgets(buf, BUFSIZ, stdin) == NULL) 447 return ((struct disklabel *)0); 448 if (buf[0] != 'n') 449 dp->d_flags |= D_BADSECT; 450 } 451 for (fp = fields; fp->f_name != NULL; fp++) { 452 again: 453 fprintf(stderr, "%s ", fp->f_name); 454 if (fp->f_defaults != NULL) 455 fprintf(stderr, "(%s)", fp->f_defaults); 456 fprintf(stderr, "? "); 457 if (fgets(buf, BUFSIZ, stdin) == NULL) 458 return ((struct disklabel *)0); 459 if ((cp = strchr(buf, '\n')) != NULL) 460 *cp = '\0'; 461 cp = buf; 462 if (*cp == '\0') { 463 if (fp->f_defaults == NULL) { 464 fprintf(stderr, "no default value\n"); 465 goto again; 466 } 467 cp = fp->f_defaults; 468 } 469 *fp->f_location = atol(cp); 470 if (*fp->f_location == 0) { 471 fprintf(stderr, "%s: bad value\n", cp); 472 goto again; 473 } 474 } 475 fprintf(stderr, "sectors/cylinder (%d)? ", 476 dp->d_nsectors * dp->d_ntracks); 477 if (fgets(buf, BUFSIZ, stdin) == NULL) 478 return ((struct disklabel *)0); 479 if ((cp = strchr(buf, '\n')) != NULL) 480 *cp = '\0'; 481 if (buf[0] == 0) 482 dp->d_secpercyl = dp->d_nsectors * dp->d_ntracks; 483 else 484 dp->d_secpercyl = atol(buf); 485 fprintf(stderr, "Drive-type-specific parameters, <cr> to terminate:\n"); 486 for (i = 0; i < NDDATA; i++) { 487 fprintf(stderr, "d%d? ", i); 488 if (fgets(buf, BUFSIZ, stdin) == NULL) 489 return ((struct disklabel *)0); 490 if ((cp = strchr(buf, '\n')) != NULL) 491 *cp = '\0'; 492 if (buf[0] == 0) 493 break; 494 dp->d_drivedata[i] = atol(buf); 495 } 496 return (dp); 497 } 498 499 int 500 gettype(t, names) 501 const char *t; 502 char **names; 503 { 504 char **nm; 505 506 for (nm = names; *nm; nm++) 507 if (strcasecmp(t, *nm) == 0) 508 return (nm - names); 509 if (isdigit(*t)) 510 return (atoi(t)); 511 return (-1); 512 } 513 514 void 515 usage(void) 516 { 517 (void)fprintf(stderr, "Usage: diskpart [-dp] [-s size] disk-type\n"); 518 exit(1); 519 } 520