xref: /freebsd/sbin/fdisk/fdisk.c (revision 17ee9d00bc1ae1e598c38f25826f861e4bc6c3ce)
1 /*
2  * Mach Operating System
3  * Copyright (c) 1992 Carnegie Mellon University
4  * All Rights Reserved.
5  *
6  * Permission to use, copy, modify and distribute this software and its
7  * documentation is hereby granted, provided that both the copyright
8  * notice and this permission notice appear in all copies of the
9  * software, derivative works or modified versions, and any portions
10  * thereof, and that both notices appear in supporting documentation.
11  *
12  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15  *
16  * Carnegie Mellon requests users of this software to return to
17  *
18  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
19  *  School of Computer Science
20  *  Carnegie Mellon University
21  *  Pittsburgh PA 15213-3890
22  *
23  * any improvements or extensions that they make and grant Carnegie Mellon
24  * the rights to redistribute these changes.
25  */
26 
27 #include <sys/types.h>
28 #include <sys/disklabel.h>
29 #include <stdio.h>
30 #include <sys/stat.h>
31 #include <sys/ioctl.h>
32 #include <fcntl.h>
33 
34 int iotest;
35 
36 #define LBUF 100
37 static char lbuf[LBUF];
38 
39 /*
40  *
41  * Ported to 386bsd by Julian Elischer  Thu Oct 15 20:26:46 PDT 1992
42  *
43  * 14-Dec-89  Robert Baron (rvb) at Carnegie-Mellon University
44  *	Copyright (c) 1989	Robert. V. Baron
45  *	Created.
46  */
47 
48 #define Decimal(str, ans, tmp) if (decimal(str, &tmp, ans)) ans = tmp
49 #define Hex(str, ans, tmp) if (hex(str, &tmp, ans)) ans = tmp
50 #define String(str, ans, len) {char *z = ans; char **dflt = &z; if (string(str, dflt)) strncpy(ans, *dflt, len); }
51 
52 #define RoundCyl(x) ((((x) + cylsecs - 1) / cylsecs) * cylsecs)
53 
54 #define SECSIZE 512
55 
56 char *disk = "/dev/rwd0d";
57 char *name;
58 
59 struct disklabel disklabel;		/* disk parameters */
60 
61 int cyls, sectors, heads, cylsecs, disksecs;
62 
63 struct mboot
64 {
65 	unsigned char padding[2]; /* force the longs to be long alligned */
66 	unsigned char bootinst[DOSPARTOFF];
67 	struct	dos_partition parts[4];
68 	unsigned short int	signature;
69 };
70 struct mboot mboot;
71 
72 #define ACTIVE 0x80
73 #define BOOT_MAGIC 0xAA55
74 
75 int dos_cyls;
76 int dos_heads;
77 int dos_sectors;
78 int dos_cylsecs;
79 
80 #define DOSSECT(s,c) ((s & 0x3f) | ((c >> 2) & 0xc0))
81 #define DOSCYL(c)	(c & 0xff)
82 static int dos();
83 char *get_type();
84 static int partition = -1;
85 
86 
87 static int a_flag  = 0;		/* set active partition */
88 static int i_flag  = 0;		/* replace partition data */
89 static int u_flag  = 0;		/* update partition data */
90 
91 static unsigned char bootcode[] = {
92 0x33, 0xc0, 0xfa, 0x8e, 0xd0, 0xbc, 0x00, 0x7c, 0x8e, 0xc0, 0x8e, 0xd8, 0xfb, 0x8b, 0xf4, 0xbf,
93 0x00, 0x06, 0xb9, 0x00, 0x02, 0xfc, 0xf3, 0xa4, 0xea, 0x1d, 0x06, 0x00, 0x00, 0xb0, 0x04, 0xbe,
94 0xbe, 0x07, 0x80, 0x3c, 0x80, 0x74, 0x0c, 0x83, 0xc6, 0x10, 0xfe, 0xc8, 0x75, 0xf4, 0xbe, 0xbd,
95 0x06, 0xeb, 0x43, 0x8b, 0xfe, 0x8b, 0x14, 0x8b, 0x4c, 0x02, 0x83, 0xc6, 0x10, 0xfe, 0xc8, 0x74,
96 0x0a, 0x80, 0x3c, 0x80, 0x75, 0xf4, 0xbe, 0xbd, 0x06, 0xeb, 0x2b, 0xbd, 0x05, 0x00, 0xbb, 0x00,
97 0x7c, 0xb8, 0x01, 0x02, 0xcd, 0x13, 0x73, 0x0c, 0x33, 0xc0, 0xcd, 0x13, 0x4d, 0x75, 0xef, 0xbe,
98 0x9e, 0x06, 0xeb, 0x12, 0x81, 0x3e, 0xfe, 0x7d, 0x55, 0xaa, 0x75, 0x07, 0x8b, 0xf7, 0xea, 0x00,
99 0x7c, 0x00, 0x00, 0xbe, 0x85, 0x06, 0x2e, 0xac, 0x0a, 0xc0, 0x74, 0x06, 0xb4, 0x0e, 0xcd, 0x10,
100 0xeb, 0xf4, 0xfb, 0xeb, 0xfe,
101 'M', 'i', 's', 's', 'i', 'n', 'g', ' ',
102 	'o', 'p', 'e', 'r', 'a', 't', 'i', 'n', 'g', ' ', 's', 'y', 's', 't', 'e', 'm', 0,
103 'E', 'r', 'r', 'o', 'r', ' ', 'l', 'o', 'a', 'd', 'i', 'n', 'g', ' ',
104 	'o', 'p', 'e', 'r', 'a', 't', 'i', 'n', 'g', ' ', 's', 'y', 's', 't', 'e', 'm', 0,
105 'I', 'n', 'v', 'a', 'l', 'i', 'd', ' ',
106 	'p', 'a', 'r', 't', 'i', 't', 'i', 'o', 'n', ' ', 't', 'a', 'b', 'l', 'e', 0,
107 'A', 'u', 't', 'h', 'o', 'r', ' ', '-', ' ',
108 	'S', 'i', 'e', 'g', 'm', 'a', 'r', ' ', 'S', 'c', 'h', 'm', 'i', 'd', 't', 0,0,0,
109 
110   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
111   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
112   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
113   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
114   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
115   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
116   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
117   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
118   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
119   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
120   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
121   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
122   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0
123 };
124 
125 struct part_type
126 {
127  unsigned char type;
128  char *name;
129 }part_types[] =
130 {
131 	 {0x00, "unused"}
132 	,{0x01, "Primary DOS with 12 bit FAT"}
133 	,{0x02, "XENIX / filesystem"}
134 	,{0x03, "XENIX /usr filesystem"}
135 	,{0x04, "Primary DOS with 16 bit FAT"}
136 	,{0x05, "Extended DOS"}
137 	,{0x06, "Primary 'big' DOS (> 32MB)"}
138 	,{0x07, "OS/2 HPFS, QNX or Advanced UNIX"}
139 	,{0x08, "AIX filesystem"}
140 	,{0x09, "AIX boot partition or Coherent"}
141 	,{0x0A, "OS/2 Boot Manager or OPUS"}
142 	,{0x10, "OPUS"}
143 	,{0x40, "VENIX 286"}
144 	,{0x50, "DM"}
145 	,{0x51, "DM"}
146 	,{0x52, "CP/M or Microport SysV/AT"}
147 	,{0x56, "GB"}
148 	,{0x61, "Speed"}
149 	,{0x63, "ISC UNIX, other System V/386, GNU HURD or Mach"}
150 	,{0x64, "Novell Netware 2.xx"}
151 	,{0x65, "Novell Netware 3.xx"}
152 	,{0x75, "PCIX"}
153 	,{0x80, "Minix 1.1 ... 1.4a"}
154 	,{0x81, "Minix 1.4b ... 1.5.10"}
155 	,{0x82, "Linux swap"}
156 	,{0x83, "Linux filesystem"}
157 	,{0x93, "Amoeba filesystem"}
158 	,{0x94, "Amoeba bad block table"}
159 	,{0xA5, "FreeBSD/NetBSD/386BSD"}
160 	,{0xB7, "BSDI BSD/386 filesystem"}
161 	,{0xB8, "BSDI BSD/386 swap"}
162 	,{0xDB, "Concurrent CPM or C.DOS or CTOS"}
163 	,{0xE1, "Speed"}
164 	,{0xE3, "Speed"}
165 	,{0xE4, "Speed"}
166 	,{0xF1, "Speed"}
167 	,{0xF2, "DOS 3.3+ Secondary"}
168 	,{0xF4, "Speed"}
169 	,{0xFF, "BBT (Bad Blocks Table)"}
170 };
171 
172 
173 main(argc, argv)
174 char **argv;
175 {
176 int	i;
177 
178 	name = *argv;
179 	{register char *cp = name;
180 		while (*cp) if (*cp++ == '/') name = cp;
181 	}
182 
183 	for ( argv++ ; --argc ; argv++ ) { register char *token = *argv;
184 		if (*token++ != '-' || !*token)
185 			break;
186 		else { register int flag;
187 			for ( ; flag = *token++ ; ) {
188 				switch (flag) {
189 				case '0':
190 					partition = 0;
191 					break;
192 				case '1':
193 					partition = 1;
194 					break;
195 				case '2':
196 					partition = 2;
197 					break;
198 				case '3':
199 					partition = 3;
200 					break;
201 				case 'a':
202 					a_flag = 1;
203 					break;
204 				case 'i':
205 					i_flag = 1;
206 				case 'u':
207 					u_flag = 1;
208 					break;
209 				default:
210 					goto usage;
211 				}
212 			}
213 		}
214 	}
215 
216 	if (argc > 0)
217 		disk = argv[0];
218 
219 	if (open_disk(u_flag) < 0)
220 		exit(1);
221 
222 	printf("******* Working on device %s *******\n",disk);
223 	if(u_flag)
224 	{
225 		get_params_to_use();
226 	}
227 	else
228 	{
229 		print_params();
230 	}
231 
232 	if (read_s0())
233 		init_sector0(1);
234 
235 	printf("Warning: BIOS sector numbering starts with sector 1\n");
236 	printf("Information from DOS bootblock is:\n");
237 	if (partition == -1)
238 		for (i = 0; i < NDOSPART; i++)
239 			change_part(i);
240 	else
241 		change_part(partition);
242 
243 	if (u_flag || a_flag)
244 		change_active(partition);
245 
246 	if (u_flag || a_flag) {
247 		printf("\nWe haven't changed the partition table yet.  ");
248 		printf("This is your last chance.\n");
249 		print_s0(-1);
250 		if (ok("Should we write new partition table?"))
251 			write_s0();
252 	}
253 
254 	exit(0);
255 
256 usage:
257 	printf("fdisk {-a|-i|-r} {disk}\n");
258 }
259 
260 print_s0(which)
261 {
262 int	i;
263 
264 	print_params();
265 	printf("Information from DOS bootblock is:\n");
266 	if (which == -1)
267 		for (i = 0; i < NDOSPART; i++)
268 			printf("%d: ", i), print_part(i);
269 	else
270 		print_part(which);
271 }
272 
273 static struct dos_partition mtpart = { 0 };
274 
275 print_part(i)
276 {
277 struct dos_partition *partp = ((struct dos_partition *) &mboot.parts) + i;
278 
279 
280 	if (!bcmp(partp, &mtpart, sizeof (struct dos_partition))) {
281 		printf("<UNUSED>\n");
282 		return;
283 	}
284 	printf("sysid %d,(%s)\n", partp->dp_typ, get_type(partp->dp_typ));
285 	printf("    start %d, size %d (%d Meg), flag %x\n",
286 		partp->dp_start,
287 		partp->dp_size, partp->dp_size * 512 / (1024 * 1024),
288 		partp->dp_flag);
289 	printf("\tbeg: cyl %d/ sector %d/ head %d;\n\tend: cyl %d/ sector %d/ head %d\n"
290 		,DPCYL(partp->dp_scyl, partp->dp_ssect)
291 		,DPSECT(partp->dp_ssect)
292 		,partp->dp_shd
293 		,DPCYL(partp->dp_ecyl, partp->dp_esect)
294 		,DPSECT(partp->dp_esect)
295 		,partp->dp_ehd);
296 }
297 
298 init_sector0(start)
299 {
300 struct dos_partition *partp = (struct dos_partition *) (&mboot.parts[3]);
301 int size = disksecs - start;
302 int rest;
303 
304 	memcpy(mboot.bootinst, bootcode, sizeof(bootcode));
305 	mboot.signature = BOOT_MAGIC;
306 
307 	partp->dp_typ = DOSPTYP_386BSD;
308 	partp->dp_flag = ACTIVE;
309 	partp->dp_start = start;
310 	partp->dp_size = size;
311 
312 	dos(partp->dp_start, &partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd);
313 	dos(partp->dp_start+partp->dp_size, &partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd);
314 }
315 
316 change_part(i)
317 {
318 struct dos_partition *partp = ((struct dos_partition *) &mboot.parts) + i;
319 
320     printf("The data for partition %d is:\n", i);
321     print_part(i);
322 
323     if (u_flag && ok("Do you want to change it?")) {
324 	int tmp;
325 
326 	if (i_flag) {
327 		bzero((char *)partp, sizeof (struct dos_partition));
328 		if (i == 3) {
329 			init_sector0(1);
330 			printf("\nThe static data for the DOS partition 3 has been reinitialized to:\n");
331 			print_part(i);
332 		}
333 	}
334 
335 	do {
336 		Decimal("sysid", partp->dp_typ, tmp);
337 		Decimal("start", partp->dp_start, tmp);
338 		Decimal("size", partp->dp_size, tmp);
339 
340 		if (ok("Explicitly specifiy beg/end address ?"))
341 		{
342 			int	tsec,tcyl,thd;
343 			tcyl = DPCYL(partp->dp_scyl,partp->dp_ssect);
344 			thd = partp->dp_shd;
345 			tsec = DPSECT(partp->dp_ssect);
346 			Decimal("beginning cylinder", tcyl, tmp);
347 			Decimal("beginning head", thd, tmp);
348 			Decimal("beginning sector", tsec, tmp);
349 			partp->dp_scyl = DOSCYL(tcyl);
350 			partp->dp_ssect = DOSSECT(tsec,tcyl);
351 			partp->dp_shd = thd;
352 
353 			tcyl = DPCYL(partp->dp_ecyl,partp->dp_esect);
354 			thd = partp->dp_ehd;
355 			tsec = DPSECT(partp->dp_esect);
356 			Decimal("ending cylinder", tcyl, tmp);
357 			Decimal("ending head", thd, tmp);
358 			Decimal("ending sector", tsec, tmp);
359 			partp->dp_ecyl = DOSCYL(tcyl);
360 			partp->dp_esect = DOSSECT(tsec,tcyl);
361 			partp->dp_ehd = thd;
362 		} else {
363 			dos(partp->dp_start,
364 				&partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd);
365 			dos(partp->dp_start+partp->dp_size - 1,
366 				&partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd);
367 		}
368 
369 		print_part(i);
370 	} while (!ok("Are we happy with this entry?"));
371     }
372 }
373 
374 print_params()
375 {
376 	printf("parameters extracted from in-core disklabel are:\n");
377 	printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n"
378 			,cyls,heads,sectors,cylsecs);
379 	if((dos_sectors > 63) || (dos_cyls > 1023) || (dos_heads > 255))
380 		printf(" Figures below won't work with BIOS for partitions not in cyl 1\n");
381 	printf("parameters to be used for BIOS calculations are:\n");
382 	printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n"
383 		,dos_cyls,dos_heads,dos_sectors,dos_cylsecs);
384 }
385 
386 change_active(which)
387 {
388 int i;
389 int active = 3, tmp;
390 struct dos_partition *partp = ((struct dos_partition *) &mboot.parts);
391 
392 	if (a_flag && which != -1)
393 		active = which;
394 	if (!ok("Do you want to change the active partition?"))
395 		return;
396 	do
397 		Decimal("active partition", active, tmp);
398 	while (!ok("Are you happy with this choice"));
399 	for (i = 0; i < NDOSPART; i++)
400 		partp[i].dp_flag = 0;
401 	if (active >= 0 && active < NDOSPART)
402 		partp[active].dp_flag = ACTIVE;
403 }
404 
405 get_params_to_use()
406 {
407 	int	tmp;
408 	print_params();
409 	if (ok("Do you want to change our idea of what BIOS thinks ?"))
410 	{
411 		do
412 		{
413 			Decimal("BIOS's idea of #cylinders", dos_cyls, tmp);
414 			Decimal("BIOS's idea of #heads", dos_heads, tmp);
415 			Decimal("BIOS's idea of #sectors", dos_sectors, tmp);
416 			dos_cylsecs = dos_heads * dos_sectors;
417 			print_params();
418 		}
419 		while(!ok("Are you happy with this choice"));
420 	}
421 }
422 
423 /***********************************************\
424 * Change real numbers into strange dos numbers	*
425 \***********************************************/
426 static
427 dos(sec, c, s, h)
428 int sec;
429 unsigned char *c, *s, *h;
430 {
431 int cy;
432 int hd;
433 
434 	if (sec == 0) {
435 		*s = *c = *h = 0;
436 		return;
437 	}
438 
439 	cy = sec / ( dos_cylsecs );
440 	sec = sec - cy * ( dos_cylsecs );
441 
442 	hd = sec / dos_sectors;
443 	sec = (sec - hd * dos_sectors) + 1;
444 
445 	*h = hd;
446 	*c = cy & 0xff;
447 	*s = (sec & 0x3f) | ( (cy & 0x300) >> 2);
448 }
449 
450 int fd;
451 
452 	/* Getting device status */
453 
454 open_disk(u_flag)
455 {
456 struct stat 	st;
457 
458 	if (stat(disk, &st) == -1) {
459 		fprintf(stderr, "%s: Can't get file status of %s\n",
460 			name, disk);
461 		return -1;
462 	}
463 	if ( !(st.st_mode & S_IFCHR) )
464 		fprintf(stderr,"%s: Device %s is not character special\n",
465 			name, disk);
466 	if ((fd = open(disk, a_flag || u_flag ? O_RDWR : O_RDONLY)) == -1) {
467 		fprintf(stderr,"%s: Can't open device %s\n", name, disk);
468 		return -1;
469 	}
470 	if (get_params(0) == -1) {
471 		fprintf(stderr, "%s: Can't get disk parameters on %s\n",
472 			name, disk);
473 		return -1;
474 	}
475 	return fd;
476 }
477 
478 
479 read_disk(sector, buf)
480 {
481 	lseek(fd,(sector * 512), 0);
482 	return read(fd, buf, 512);
483 }
484 
485 write_disk(sector, buf)
486 {
487 	lseek(fd,(sector * 512), 0);
488 	return write(fd, buf, 512);
489 }
490 
491 get_params(verbose)
492 {
493 
494     if (ioctl(fd, DIOCGDINFO, &disklabel) == -1) {
495 	fprintf(stderr,
496 		"%s: Can't get disk parameters on %s; supplying dummy ones\n",
497 		name, disk);
498 	dos_cyls = cyls = 1;
499 	dos_heads = heads = 1;
500 	dos_sectors = sectors = 1;
501 	dos_cylsecs = cylsecs = heads * sectors;
502 	disksecs = cyls * heads * sectors;
503 	return disksecs;
504     }
505 
506     dos_cyls = cyls = disklabel.d_ncylinders;
507     dos_heads = heads = disklabel.d_ntracks;
508     dos_sectors = sectors = disklabel.d_nsectors;
509     dos_cylsecs = cylsecs = heads * sectors;
510     disksecs = cyls * heads * sectors;
511 
512     return (disksecs);
513 }
514 
515 
516 read_s0()
517 {
518 	if (read_disk(0, (char *) mboot.bootinst) == -1) {
519 		fprintf(stderr, "%s: Can't read fdisk partition table\n", name);
520 		return -1;
521 	}
522 	if (mboot.signature != BOOT_MAGIC) {
523 		fprintf(stderr, "%s: Invalid fdisk partition table found\n",
524 			name);
525 		/* So should we initialize things */
526 		return -1;
527 	}
528 	return 0;
529 }
530 
531 write_s0()
532 {
533 	int	flag;
534 	if (iotest) {
535 		print_s0(-1);
536 		return 0;
537 	}
538 	/*
539 	 * write enable label sector before write (if necessary),
540 	 * disable after writing.
541 	 * needed if the disklabel protected area also protects
542 	 * sector 0. (e.g. empty disk)
543 	 */
544 	flag = 1;
545 	if (ioctl(fd, DIOCWLABEL, &flag) < 0)
546 		perror("ioctl DIOCWLABEL");
547 	if (write_disk(0, (char *) mboot.bootinst) == -1) {
548 		fprintf(stderr, "%s: Can't write fdisk partition table\n",
549 			name);
550 		return -1;
551 	flag = 0;
552 	(void) ioctl(fd, DIOCWLABEL, &flag);
553 	}
554 }
555 
556 
557 
558 ok(str)
559 char *str;
560 {
561 	printf("%s [n] ", str);
562 	fgets(lbuf, LBUF, stdin);
563 	lbuf[strlen(lbuf)-1] = 0;
564 
565 	if (*lbuf &&
566 		(!strcmp(lbuf, "yes") || !strcmp(lbuf, "YES") ||
567 		 !strcmp(lbuf, "y") || !strcmp(lbuf, "Y")))
568 		return 1;
569 	else
570 		return 0;
571 }
572 
573 decimal(str, num, deflt)
574 char *str;
575 int *num;
576 {
577 int acc = 0, c;
578 char *cp;
579 
580 	while (1) {
581 		printf("Supply a decimal value for \"%s\" [%d] ", str, deflt);
582 		fgets(lbuf, LBUF, stdin);
583 		lbuf[strlen(lbuf)-1] = 0;
584 
585 		if (!*lbuf)
586 			return 0;
587 
588 		cp = lbuf;
589 		while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
590 		if (!c)
591 			return 0;
592 		while (c = *cp++) {
593 			if (c <= '9' && c >= '0')
594 				acc = acc * 10 + c - '0';
595 			else
596 				break;
597 		}
598 		if (c == ' ' || c == '\t')
599 			while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
600 		if (!c) {
601 			*num = acc;
602 			return 1;
603 		} else
604 			printf("%s is an invalid decimal number.  Try again\n",
605 				lbuf);
606 	}
607 
608 }
609 
610 hex(str, num, deflt)
611 char *str;
612 int *num;
613 {
614 int acc = 0, c;
615 char *cp;
616 
617 	while (1) {
618 		printf("Supply a hex value for \"%s\" [%x] ", str, deflt);
619 		fgets(lbuf, LBUF, stdin);
620 		lbuf[strlen(lbuf)-1] = 0;
621 
622 		if (!*lbuf)
623 			return 0;
624 
625 		cp = lbuf;
626 		while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
627 		if (!c)
628 			return 0;
629 		while (c = *cp++) {
630 			if (c <= '9' && c >= '0')
631 				acc = (acc << 4) + c - '0';
632 			else if (c <= 'f' && c >= 'a')
633 				acc = (acc << 4) + c - 'a' + 10;
634 			else if (c <= 'F' && c >= 'A')
635 				acc = (acc << 4) + c - 'A' + 10;
636 			else
637 				break;
638 		}
639 		if (c == ' ' || c == '\t')
640 			while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
641 		if (!c) {
642 			*num = acc;
643 			return 1;
644 		} else
645 			printf("%s is an invalid hex number.  Try again\n",
646 				lbuf);
647 	}
648 
649 }
650 
651 string(str, ans)
652 char *str;
653 char **ans;
654 {
655 int c;
656 char *cp = lbuf;
657 
658 	while (1) {
659 		printf("Supply a string value for \"%s\" [%s] ", str, *ans);
660 		fgets(lbuf, LBUF, stdin);
661 		lbuf[strlen(lbuf)-1] = 0;
662 
663 		if (!*lbuf)
664 			return 0;
665 
666 		while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
667 		if (c == '"') {
668 			c = *++cp;
669 			*ans = cp;
670 			while ((c = *cp) && c != '"') cp++;
671 		} else {
672 			*ans = cp;
673 			while ((c = *cp) && c != ' ' && c != '\t') cp++;
674 		}
675 
676 		if (c)
677 			*cp = 0;
678 		return 1;
679 	}
680 }
681 
682 char *get_type(type)
683 int	type;
684 {
685 	int	numentries = (sizeof(part_types)/sizeof(struct part_type));
686 	int	counter = 0;
687 	struct	part_type *ptr = part_types;
688 
689 
690 	while(counter < numentries)
691 	{
692 		if(ptr->type == type)
693 		{
694 			return(ptr->name);
695 		}
696 		ptr++;
697 		counter++;
698 	}
699 	return("unknown");
700 }
701