1 /*
2  * Copyright (c) 1983 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 
18 #ifndef lint
19 char copyright[] =
20 "@(#) Copyright (c) 1983 Regents of the University of California.\n\
21  All rights reserved.\n";
22 #endif /* not lint */
23 
24 #ifndef lint
25 static char sccsid[] = "@(#)diskpart.c	5.9 (Berkeley) 06/18/88";
26 #endif /* not lint */
27 
28 /*
29  * Program to calculate standard disk partition sizes.
30  */
31 #include <sys/param.h>
32 #define DKTYPENAMES
33 #include <sys/disklabel.h>
34 
35 #include <stdio.h>
36 #include <ctype.h>
37 
38 #define	for_now			/* show all of `c' partition for disklabel */
39 #define	NPARTITIONS	8
40 #define	PART(x)		(x - 'a')
41 
42 /*
43  * Default partition sizes, where they exist.
44  */
45 #define	NDEFAULTS	4
46 int	defpart[NDEFAULTS][NPARTITIONS] = {
47    { 15884, 66880, 0, 15884, 307200, 0, 0, 291346 },	/* ~ 356+ Mbytes */
48    { 15884, 33440, 0, 15884, 55936, 0, 0, 291346 },	/* ~ 206-355 Mbytes */
49    { 15884, 33440, 0, 15884, 55936, 0, 0, 0 },		/* ~ 61-205 Mbytes */
50    { 15884, 10032, 0, 15884, 0, 0, 0, 0 },		/* ~ 20-60 Mbytes */
51 };
52 
53 /*
54  * Each array defines a layout for a disk;
55  * that is, the collection of partitions totally
56  * covers the physical space on a disk.
57  */
58 #define	NLAYOUTS	3
59 char	layouts[NLAYOUTS][NPARTITIONS] = {
60    { 'a', 'b', 'h', 'g' },
61    { 'a', 'b', 'h', 'd', 'e', 'f' },
62    { 'c' },
63 };
64 
65 /*
66  * Default disk block and disk block fragment
67  * sizes for each file system.  Those file systems
68  * with zero block and frag sizes are special cases
69  * (e.g. swap areas or for access to the entire device).
70  */
71 struct	partition defparam[NPARTITIONS] = {
72 	{ 0, 0, 1024, FS_UNUSED, 8, 0 },		/* a */
73 	{ 0, 0, 1024, FS_SWAP,   8, 0 },		/* b */
74 	{ 0, 0, 1024, FS_UNUSED, 8, 0 },		/* c */
75 	{ 0, 0,  512, FS_UNUSED, 8, 0 },		/* d */
76 	{ 0, 0, 1024, FS_UNUSED, 8, 0 },		/* e */
77 	{ 0, 0, 1024, FS_UNUSED, 8, 0 },		/* f */
78 	{ 0, 0, 1024, FS_UNUSED, 8, 0 },		/* g */
79 	{ 0, 0, 1024, FS_UNUSED, 8, 0 }			/* h */
80 };
81 
82 /*
83  * Each disk has some space reserved for a bad sector
84  * forwarding table.  DEC standard 144 uses the first
85  * 5 even numbered sectors in the last track of the
86  * last cylinder for replicated storage of the bad sector
87  * table; another 126 sectors past this is needed as a
88  * pool of replacement sectors.
89  */
90 int	badsecttable = 126;	/* # sectors */
91 
92 int	pflag;			/* print device driver partition tables */
93 int	dflag;			/* print disktab entry */
94 
95 struct	disklabel *promptfordisk();
96 
97 main(argc, argv)
98 	int argc;
99 	char *argv[];
100 {
101 	struct disklabel *dp;
102 	register int curcyl, spc, def, part, layout, j;
103 	int threshhold, numcyls[NPARTITIONS], startcyl[NPARTITIONS];
104 	char *lp;
105 
106 	argc--, argv++;
107 	if (argc < 1) {
108 		fprintf(stderr, "usage: disktab [ -p ] [ -d ] disk-type\n");
109 		exit(1);
110 	}
111 	if (argc > 0 && strcmp(*argv, "-p") == 0) {
112 		pflag++;
113 		argc--, argv++;
114 	}
115 	if (argc > 0 && strcmp(*argv, "-d") == 0) {
116 		dflag++;
117 		argc--, argv++;
118 	}
119 	dp = getdiskbyname(*argv);
120 	if (dp == NULL) {
121 		if (isatty(0))
122 			dp = promptfordisk(*argv);
123 		if (dp == NULL) {
124 			fprintf(stderr, "%s: unknown disk type\n", *argv);
125 			exit(2);
126 		}
127 	} else {
128 		if (dp->d_flags & D_REMOVABLE)
129 			strncpy(dp->d_typename, "removable",
130 			    sizeof(dp->d_typename));
131 		else if (dp->d_flags & D_RAMDISK)
132 			strncpy(dp->d_typename, "simulated",
133 			    sizeof(dp->d_typename));
134 		else
135 			strncpy(dp->d_typename, "winchester",
136 			    sizeof(dp->d_typename));
137 	}
138 	spc = dp->d_secpercyl;
139 	/*
140 	 * Bad sector table contains one track for the replicated
141 	 * copies of the table and enough full tracks preceding
142 	 * the last track to hold the pool of free blocks to which
143 	 * bad sectors are mapped.
144 	 */
145 	if (dp->d_type == DTYPE_SMD && dp->d_flags & D_BADSECT) {
146 		badsecttable = dp->d_nsectors +
147 		    roundup(badsecttable, dp->d_nsectors);
148 		threshhold = howmany(spc, badsecttable);
149 	} else {
150 		badsecttable = 0;
151 		threshhold = 0;
152 	}
153 
154 	/*
155 	 * Figure out if disk is large enough for
156 	 * expanded swap area and 'd', 'e', and 'f'
157 	 * partitions.  Otherwise, use smaller defaults
158 	 * based on RK07.
159 	 */
160 	for (def = 0; def < NDEFAULTS; def++) {
161 		curcyl = 0;
162 		for (part = PART('a'); part < NPARTITIONS; part++)
163 			curcyl += howmany(defpart[def][part], spc);
164 		if (curcyl < dp->d_ncylinders - threshhold)
165 			break;
166 	}
167 	if (def >= NDEFAULTS) {
168 		fprintf(stderr, "%s: disk too small, calculate by hand\n",
169 			*argv);
170 		exit(3);
171 	}
172 
173 	/*
174 	 * Calculate number of cylinders allocated to each disk
175 	 * partition.  We may waste a bit of space here, but it's
176 	 * in the interest of compatibility (for mixed disk systems).
177 	 */
178 	for (curcyl = 0, part = PART('a'); part < NPARTITIONS; part++) {
179 		numcyls[part] = 0;
180 		if (defpart[def][part] != 0) {
181 			numcyls[part] = howmany(defpart[def][part], spc);
182 			curcyl += numcyls[part];
183 		}
184 	}
185 	numcyls[PART('f')] = dp->d_ncylinders - curcyl;
186 	numcyls[PART('g')] =
187 		numcyls[PART('d')] + numcyls[PART('e')] + numcyls[PART('f')];
188 	numcyls[PART('c')] = dp->d_ncylinders;
189 	defpart[def][PART('f')] = numcyls[PART('f')] * spc - badsecttable;
190 	defpart[def][PART('g')] = numcyls[PART('g')] * spc - badsecttable;
191 	defpart[def][PART('c')] = numcyls[PART('c')] * spc;
192 #ifndef for_now
193 	if (!pflag)
194 		defpart[def][PART('c')] -= badsecttable;
195 #endif
196 
197 	/*
198 	 * Calculate starting cylinder number for each partition.
199 	 * Note the 'h' partition is physically located before the
200 	 * 'g' or 'd' partition.  This is reflected in the layout
201 	 * arrays defined above.
202 	 */
203 	for (layout = 0; layout < NLAYOUTS; layout++) {
204 		curcyl = 0;
205 		for (lp = layouts[layout]; *lp != 0; lp++) {
206 			startcyl[PART(*lp)] = curcyl;
207 			curcyl += numcyls[PART(*lp)];
208 		}
209 	}
210 
211 	if (pflag) {
212 		printf("}, %s_sizes[%d] = {\n", dp->d_typename, NPARTITIONS);
213 		for (part = PART('a'); part < NPARTITIONS; part++) {
214 			if (numcyls[part] == 0) {
215 				printf("\t0,\t0,\n");
216 				continue;
217 			}
218 			if (dp->d_type != DTYPE_MSCP) {
219 			       printf("\t%d,\t%d,\t\t/* %c=cyl %d thru %d */\n",
220 					defpart[def][part], startcyl[part],
221 					'A' + part, startcyl[part],
222 					startcyl[part] + numcyls[part] - 1);
223 				continue;
224 			}
225 			printf("\t%d,\t%d,\t\t/* %c=sectors %d thru %d */\n",
226 				defpart[def][part], spc * startcyl[part],
227 				'A' + part, spc * startcyl[part],
228 				spc * startcyl[part] + defpart[def][part] - 1);
229 		}
230 		exit(0);
231 	}
232 	if (dflag) {
233 		int nparts;
234 
235 		/*
236 		 * In case the disk is in the ``in-between'' range
237 		 * where the 'g' partition is smaller than the 'h'
238 		 * partition, reverse the frag sizes so the /usr partition
239 		 * is always set up with a frag size larger than the
240 		 * user's partition.
241 		 */
242 		if (defpart[def][PART('g')] < defpart[def][PART('h')]) {
243 			int temp;
244 
245 			temp = defparam[PART('h')].p_fsize;
246 			defparam[PART('h')].p_fsize =
247 				defparam[PART('g')].p_fsize;
248 			defparam[PART('g')].p_fsize = temp;
249 		}
250 		printf("%s:\\\n", dp->d_typename);
251 		printf("\t:ty=%s:ns#%d:nt#%d:nc#%d:", dp->d_typename,
252 			dp->d_nsectors, dp->d_ntracks, dp->d_ncylinders);
253 		if (dp->d_secpercyl != dp->d_nsectors * dp->d_ntracks)
254 			printf("sc#%d:", dp->d_secpercyl);
255 		if (dp->d_type == DTYPE_SMD && dp->d_flags & D_BADSECT)
256 			printf("sf:");
257 		printf("\\\n\t:dt=%s:", dktypenames[dp->d_type]);
258 		for (part = NDDATA - 1; part >= 0; part--)
259 			if (dp->d_drivedata[part])
260 				break;
261 		for (j = 0; j <= part; j++)
262 			printf("d%d#%d:", j, dp->d_drivedata[j]);
263 		printf("\\\n");
264 		for (nparts = 0, part = PART('a'); part < NPARTITIONS; part++)
265 			if (defpart[def][part] != 0)
266 				nparts++;
267 		for (part = PART('a'); part < NPARTITIONS; part++) {
268 			if (defpart[def][part] == 0)
269 				continue;
270 			printf("\t:p%c#%d:", 'a' + part, defpart[def][part]);
271 			printf("o%c#%d:b%c#%d:f%c#%d:",
272 			    'a' + part, spc * startcyl[part],
273 			    'a' + part,
274 			    defparam[part].p_frag * defparam[part].p_fsize,
275 			    'a' + part, defparam[part].p_fsize);
276 			if (defparam[part].p_fstype == FS_SWAP)
277 				printf("t%c=swap:", 'a' + part);
278 			nparts--;
279 			printf("%s\n", nparts > 0 ? "\\" : "");
280 		}
281 #ifdef for_now
282 		defpart[def][PART('c')] -= badsecttable;
283 		part = PART('c');
284 		printf("#\t:p%c#%d:", 'a' + part, defpart[def][part]);
285 		printf("o%c#%d:b%c#%d:f%c#%d:\n",
286 		    'a' + part, spc * startcyl[part],
287 		    'a' + part,
288 		    defparam[part].p_frag * defparam[part].p_fsize,
289 		    'a' + part, defparam[part].p_fsize);
290 #endif
291 		exit(0);
292 	}
293 	printf("%s: #sectors/track=%d, #tracks/cylinder=%d #cylinders=%d\n",
294 		dp->d_typename, dp->d_nsectors, dp->d_ntracks,
295 		dp->d_ncylinders);
296 	printf("\n    Partition\t   Size\t   Range\n");
297 	for (part = PART('a'); part < NPARTITIONS; part++) {
298 		printf("\t%c\t", 'a' + part);
299 		if (numcyls[part] == 0) {
300 			printf(" unused\n");
301 			continue;
302 		}
303 		printf("%7d\t%4d - %d\n", defpart[def][part], startcyl[part],
304 			startcyl[part] + numcyls[part] - 1);
305 	}
306 }
307 
308 struct disklabel disk;
309 
310 struct	field {
311 	char	*f_name;
312 	char	*f_defaults;
313 	u_long	*f_location;
314 } fields[] = {
315 	{ "sector size",		"512",	&disk.d_secsize },
316 	{ "#sectors/track",		0,	&disk.d_nsectors },
317 	{ "#tracks/cylinder",		0,	&disk.d_ntracks },
318 	{ "#cylinders",			0,	&disk.d_ncylinders },
319 	{ 0, 0, 0 },
320 };
321 
322 struct disklabel *
323 promptfordisk(name)
324 	char *name;
325 {
326 	register struct disklabel *dp = &disk;
327 	register struct field *fp;
328 	register i;
329 	char buf[BUFSIZ], **tp, *cp, *gets();
330 
331 	strncpy(dp->d_typename, name, sizeof(dp->d_typename));
332 	fprintf(stderr,
333 		"%s: unknown disk type, want to supply parameters (y/n)? ",
334 		name);
335 	(void) gets(buf);
336 	if (*buf != 'y')
337 		return ((struct disklabel *)0);
338 	for (;;) {
339 		fprintf(stderr, "Disk/controller type (%s)? ", dktypenames[1]);
340 		(void) gets(buf);
341 		if (buf[0] == 0)
342 			dp->d_type = 1;
343 		else
344 			dp->d_type = gettype(buf, dktypenames);
345 		if (dp->d_type >= 0)
346 			break;
347 		fprintf(stderr, "%s: unrecognized controller type\n", buf);
348 		fprintf(stderr, "use one of:\n", buf);
349 		for (tp = dktypenames; *tp; tp++)
350 			if (index(*tp, ' ') == 0)
351 				fprintf(stderr, "\t%s\n", *tp);
352 	}
353 gettype:
354 	dp->d_flags = 0;
355 	fprintf(stderr, "type (winchester|removable|simulated)? ");
356 	(void) gets(buf);
357 	if (strcmp(buf, "removable") == 0)
358 		dp->d_flags = D_REMOVABLE;
359 	else if (strcmp(buf, "simulated") == 0)
360 		dp->d_flags = D_RAMDISK;
361 	else if (strcmp(buf, "winchester")) {
362 		fprintf(stderr, "%s: bad disk type\n", buf);
363 		goto gettype;
364 	}
365 	strncpy(dp->d_typename, buf, sizeof(dp->d_typename));
366 	fprintf(stderr, "(type <cr> to get default value, if only one)\n");
367 	if (dp->d_type == DTYPE_SMD)
368 	   fprintf(stderr, "Do %ss support bad144 bad block forwarding (yes)? ",
369 		dp->d_typename);
370 	(void) gets(buf);
371 	if (*buf != 'n')
372 		dp->d_flags |= D_BADSECT;
373 	for (fp = fields; fp->f_name != NULL; fp++) {
374 again:
375 		fprintf(stderr, "%s ", fp->f_name);
376 		if (fp->f_defaults != NULL)
377 			fprintf(stderr, "(%s)", fp->f_defaults);
378 		fprintf(stderr, "? ");
379 		cp = gets(buf);
380 		if (*cp == '\0') {
381 			if (fp->f_defaults == NULL) {
382 				fprintf(stderr, "no default value\n");
383 				goto again;
384 			}
385 			cp = fp->f_defaults;
386 		}
387 		*fp->f_location = atol(cp);
388 		if (*fp->f_location == 0) {
389 			fprintf(stderr, "%s: bad value\n", cp);
390 			goto again;
391 		}
392 	}
393 	fprintf(stderr, "sectors/cylinder (%d)? ",
394 	    dp->d_nsectors * dp->d_ntracks);
395 	(void) gets(buf);
396 	if (buf[0] == 0)
397 		dp->d_secpercyl = dp->d_nsectors * dp->d_ntracks;
398 	else
399 		dp->d_secpercyl = atol(buf);
400 	fprintf(stderr, "Drive-type-specific parameters, <cr> to terminate:\n");
401 	for (i = 0; i < NDDATA; i++) {
402 		fprintf(stderr, "d%d? ", i);
403 		(void) gets(buf);
404 		if (buf[0] == 0)
405 			break;
406 		dp->d_drivedata[i] = atol(buf);
407 	}
408 	return (dp);
409 }
410 
411 gettype(t, names)
412 	char *t;
413 	char **names;
414 {
415 	register char **nm;
416 
417 	for (nm = names; *nm; nm++)
418 		if (ustrcmp(t, *nm) == 0)
419 			return (nm - names);
420 	if (isdigit(*t))
421 		return (atoi(t));
422 	return (-1);
423 }
424 
425 ustrcmp(s1, s2)
426 	register char *s1, *s2;
427 {
428 #define	lower(c)	(islower(c) ? (c) : tolower(c))
429 
430 	for (; *s1; s1++, s2++) {
431 		if (*s1 == *s2)
432 			continue;
433 		if (isalpha(*s1) && isalpha(*s2) &&
434 		    lower(*s1) == lower(*s2))
435 			continue;
436 		return (*s2 - *s1);
437 	}
438 	return (0);
439 }
440