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