xref: /freebsd/sbin/fdisk/fdisk.c (revision 5ebc7e6281887681c3a348a5a4c902e262ccd656)
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 	,{0xA7, "NEXTSTEP"}
161 	,{0xB7, "BSDI BSD/386 filesystem"}
162 	,{0xB8, "BSDI BSD/386 swap"}
163 	,{0xDB, "Concurrent CPM or C.DOS or CTOS"}
164 	,{0xE1, "Speed"}
165 	,{0xE3, "Speed"}
166 	,{0xE4, "Speed"}
167 	,{0xF1, "Speed"}
168 	,{0xF2, "DOS 3.3+ Secondary"}
169 	,{0xF4, "Speed"}
170 	,{0xFF, "BBT (Bad Blocks Table)"}
171 };
172 
173 
174 main(argc, argv)
175 char **argv;
176 {
177 int	i;
178 
179 	name = *argv;
180 	{register char *cp = name;
181 		while (*cp) if (*cp++ == '/') name = cp;
182 	}
183 
184 	for ( argv++ ; --argc ; argv++ ) { register char *token = *argv;
185 		if (*token++ != '-' || !*token)
186 			break;
187 		else { register int flag;
188 			for ( ; flag = *token++ ; ) {
189 				switch (flag) {
190 				case '0':
191 					partition = 0;
192 					break;
193 				case '1':
194 					partition = 1;
195 					break;
196 				case '2':
197 					partition = 2;
198 					break;
199 				case '3':
200 					partition = 3;
201 					break;
202 				case 'a':
203 					a_flag = 1;
204 					break;
205 				case 'i':
206 					i_flag = 1;
207 				case 'u':
208 					u_flag = 1;
209 					break;
210 				default:
211 					goto usage;
212 				}
213 			}
214 		}
215 	}
216 
217 	if (argc > 0)
218 		disk = argv[0];
219 
220 	if (open_disk(u_flag) < 0)
221 		exit(1);
222 
223 	printf("******* Working on device %s *******\n",disk);
224 	if(u_flag)
225 	{
226 		get_params_to_use();
227 	}
228 	else
229 	{
230 		print_params();
231 	}
232 
233 	if (read_s0())
234 		init_sector0(1);
235 
236 	printf("Warning: BIOS sector numbering starts with sector 1\n");
237 	printf("Information from DOS bootblock is:\n");
238 	if (partition == -1)
239 		for (i = 0; i < NDOSPART; i++)
240 			change_part(i);
241 	else
242 		change_part(partition);
243 
244 	if (u_flag || a_flag)
245 		change_active(partition);
246 
247 	if (u_flag || a_flag) {
248 		printf("\nWe haven't changed the partition table yet.  ");
249 		printf("This is your last chance.\n");
250 		print_s0(-1);
251 		if (ok("Should we write new partition table?"))
252 			write_s0();
253 	}
254 
255 	exit(0);
256 
257 usage:
258 	printf("fdisk {-a|-i|-r} {disk}\n");
259 }
260 
261 print_s0(which)
262 {
263 int	i;
264 
265 	print_params();
266 	printf("Information from DOS bootblock is:\n");
267 	if (which == -1)
268 		for (i = 0; i < NDOSPART; i++)
269 			printf("%d: ", i), print_part(i);
270 	else
271 		print_part(which);
272 }
273 
274 static struct dos_partition mtpart = { 0 };
275 
276 print_part(i)
277 {
278 struct dos_partition *partp = ((struct dos_partition *) &mboot.parts) + i;
279 
280 
281 	if (!bcmp(partp, &mtpart, sizeof (struct dos_partition))) {
282 		printf("<UNUSED>\n");
283 		return;
284 	}
285 	printf("sysid %d,(%s)\n", partp->dp_typ, get_type(partp->dp_typ));
286 	printf("    start %d, size %d (%d Meg), flag %x\n",
287 		partp->dp_start,
288 		partp->dp_size, partp->dp_size * 512 / (1024 * 1024),
289 		partp->dp_flag);
290 	printf("\tbeg: cyl %d/ sector %d/ head %d;\n\tend: cyl %d/ sector %d/ head %d\n"
291 		,DPCYL(partp->dp_scyl, partp->dp_ssect)
292 		,DPSECT(partp->dp_ssect)
293 		,partp->dp_shd
294 		,DPCYL(partp->dp_ecyl, partp->dp_esect)
295 		,DPSECT(partp->dp_esect)
296 		,partp->dp_ehd);
297 }
298 
299 init_sector0(start)
300 {
301 struct dos_partition *partp = (struct dos_partition *) (&mboot.parts[3]);
302 int size = disksecs - start;
303 int rest;
304 
305 	memcpy(mboot.bootinst, bootcode, sizeof(bootcode));
306 	mboot.signature = BOOT_MAGIC;
307 
308 	partp->dp_typ = DOSPTYP_386BSD;
309 	partp->dp_flag = ACTIVE;
310 	partp->dp_start = start;
311 	partp->dp_size = size;
312 
313 	dos(partp->dp_start, &partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd);
314 	dos(partp->dp_start+partp->dp_size, &partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd);
315 }
316 
317 change_part(i)
318 {
319 struct dos_partition *partp = ((struct dos_partition *) &mboot.parts) + i;
320 
321     printf("The data for partition %d is:\n", i);
322     print_part(i);
323 
324     if (u_flag && ok("Do you want to change it?")) {
325 	int tmp;
326 
327 	if (i_flag) {
328 		bzero((char *)partp, sizeof (struct dos_partition));
329 		if (i == 3) {
330 			init_sector0(1);
331 			printf("\nThe static data for the DOS partition 3 has been reinitialized to:\n");
332 			print_part(i);
333 		}
334 	}
335 
336 	do {
337 		Decimal("sysid", partp->dp_typ, tmp);
338 		Decimal("start", partp->dp_start, tmp);
339 		Decimal("size", partp->dp_size, tmp);
340 
341 		if (ok("Explicitly specifiy beg/end address ?"))
342 		{
343 			int	tsec,tcyl,thd;
344 			tcyl = DPCYL(partp->dp_scyl,partp->dp_ssect);
345 			thd = partp->dp_shd;
346 			tsec = DPSECT(partp->dp_ssect);
347 			Decimal("beginning cylinder", tcyl, tmp);
348 			Decimal("beginning head", thd, tmp);
349 			Decimal("beginning sector", tsec, tmp);
350 			partp->dp_scyl = DOSCYL(tcyl);
351 			partp->dp_ssect = DOSSECT(tsec,tcyl);
352 			partp->dp_shd = thd;
353 
354 			tcyl = DPCYL(partp->dp_ecyl,partp->dp_esect);
355 			thd = partp->dp_ehd;
356 			tsec = DPSECT(partp->dp_esect);
357 			Decimal("ending cylinder", tcyl, tmp);
358 			Decimal("ending head", thd, tmp);
359 			Decimal("ending sector", tsec, tmp);
360 			partp->dp_ecyl = DOSCYL(tcyl);
361 			partp->dp_esect = DOSSECT(tsec,tcyl);
362 			partp->dp_ehd = thd;
363 		} else {
364 			dos(partp->dp_start,
365 				&partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd);
366 			dos(partp->dp_start+partp->dp_size - 1,
367 				&partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd);
368 		}
369 
370 		print_part(i);
371 	} while (!ok("Are we happy with this entry?"));
372     }
373 }
374 
375 print_params()
376 {
377 	printf("parameters extracted from in-core disklabel are:\n");
378 	printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n"
379 			,cyls,heads,sectors,cylsecs);
380 	if((dos_sectors > 63) || (dos_cyls > 1023) || (dos_heads > 255))
381 		printf(" Figures below won't work with BIOS for partitions not in cyl 1\n");
382 	printf("parameters to be used for BIOS calculations are:\n");
383 	printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n"
384 		,dos_cyls,dos_heads,dos_sectors,dos_cylsecs);
385 }
386 
387 change_active(which)
388 {
389 int i;
390 int active = 3, tmp;
391 struct dos_partition *partp = ((struct dos_partition *) &mboot.parts);
392 
393 	if (a_flag && which != -1)
394 		active = which;
395 	if (!ok("Do you want to change the active partition?"))
396 		return;
397 	do
398 		Decimal("active partition", active, tmp);
399 	while (!ok("Are you happy with this choice"));
400 	for (i = 0; i < NDOSPART; i++)
401 		partp[i].dp_flag = 0;
402 	if (active >= 0 && active < NDOSPART)
403 		partp[active].dp_flag = ACTIVE;
404 }
405 
406 get_params_to_use()
407 {
408 	int	tmp;
409 	print_params();
410 	if (ok("Do you want to change our idea of what BIOS thinks ?"))
411 	{
412 		do
413 		{
414 			Decimal("BIOS's idea of #cylinders", dos_cyls, tmp);
415 			Decimal("BIOS's idea of #heads", dos_heads, tmp);
416 			Decimal("BIOS's idea of #sectors", dos_sectors, tmp);
417 			dos_cylsecs = dos_heads * dos_sectors;
418 			print_params();
419 		}
420 		while(!ok("Are you happy with this choice"));
421 	}
422 }
423 
424 /***********************************************\
425 * Change real numbers into strange dos numbers	*
426 \***********************************************/
427 static
428 dos(sec, c, s, h)
429 int sec;
430 unsigned char *c, *s, *h;
431 {
432 int cy;
433 int hd;
434 
435 	if (sec == 0) {
436 		*s = *c = *h = 0;
437 		return;
438 	}
439 
440 	cy = sec / ( dos_cylsecs );
441 	sec = sec - cy * ( dos_cylsecs );
442 
443 	hd = sec / dos_sectors;
444 	sec = (sec - hd * dos_sectors) + 1;
445 
446 	*h = hd;
447 	*c = cy & 0xff;
448 	*s = (sec & 0x3f) | ( (cy & 0x300) >> 2);
449 }
450 
451 int fd;
452 
453 	/* Getting device status */
454 
455 open_disk(u_flag)
456 {
457 struct stat 	st;
458 
459 	if (stat(disk, &st) == -1) {
460 		fprintf(stderr, "%s: Can't get file status of %s\n",
461 			name, disk);
462 		return -1;
463 	}
464 	if ( !(st.st_mode & S_IFCHR) )
465 		fprintf(stderr,"%s: Device %s is not character special\n",
466 			name, disk);
467 	if ((fd = open(disk, a_flag || u_flag ? O_RDWR : O_RDONLY)) == -1) {
468 		fprintf(stderr,"%s: Can't open device %s\n", name, disk);
469 		return -1;
470 	}
471 	if (get_params(0) == -1) {
472 		fprintf(stderr, "%s: Can't get disk parameters on %s\n",
473 			name, disk);
474 		return -1;
475 	}
476 	return fd;
477 }
478 
479 
480 read_disk(sector, buf)
481 {
482 	lseek(fd,(sector * 512), 0);
483 	return read(fd, buf, 512);
484 }
485 
486 write_disk(sector, buf)
487 {
488 	lseek(fd,(sector * 512), 0);
489 	return write(fd, buf, 512);
490 }
491 
492 get_params(verbose)
493 {
494 
495     if (ioctl(fd, DIOCGDINFO, &disklabel) == -1) {
496 	fprintf(stderr,
497 		"%s: Can't get disk parameters on %s; supplying dummy ones\n",
498 		name, disk);
499 	dos_cyls = cyls = 1;
500 	dos_heads = heads = 1;
501 	dos_sectors = sectors = 1;
502 	dos_cylsecs = cylsecs = heads * sectors;
503 	disksecs = cyls * heads * sectors;
504 	return disksecs;
505     }
506 
507     dos_cyls = cyls = disklabel.d_ncylinders;
508     dos_heads = heads = disklabel.d_ntracks;
509     dos_sectors = sectors = disklabel.d_nsectors;
510     dos_cylsecs = cylsecs = heads * sectors;
511     disksecs = cyls * heads * sectors;
512 
513     return (disksecs);
514 }
515 
516 
517 read_s0()
518 {
519 	if (read_disk(0, (char *) mboot.bootinst) == -1) {
520 		fprintf(stderr, "%s: Can't read fdisk partition table\n", name);
521 		return -1;
522 	}
523 	if (mboot.signature != BOOT_MAGIC) {
524 		fprintf(stderr, "%s: Invalid fdisk partition table found\n",
525 			name);
526 		/* So should we initialize things */
527 		return -1;
528 	}
529 	return 0;
530 }
531 
532 write_s0()
533 {
534 	int	flag;
535 	if (iotest) {
536 		print_s0(-1);
537 		return 0;
538 	}
539 	/*
540 	 * write enable label sector before write (if necessary),
541 	 * disable after writing.
542 	 * needed if the disklabel protected area also protects
543 	 * sector 0. (e.g. empty disk)
544 	 */
545 	flag = 1;
546 	if (ioctl(fd, DIOCWLABEL, &flag) < 0)
547 		perror("ioctl DIOCWLABEL");
548 	if (write_disk(0, (char *) mboot.bootinst) == -1) {
549 		fprintf(stderr, "%s: Can't write fdisk partition table\n",
550 			name);
551 		return -1;
552 	flag = 0;
553 	(void) ioctl(fd, DIOCWLABEL, &flag);
554 	}
555 }
556 
557 
558 
559 ok(str)
560 char *str;
561 {
562 	printf("%s [n] ", str);
563 	fgets(lbuf, LBUF, stdin);
564 	lbuf[strlen(lbuf)-1] = 0;
565 
566 	if (*lbuf &&
567 		(!strcmp(lbuf, "yes") || !strcmp(lbuf, "YES") ||
568 		 !strcmp(lbuf, "y") || !strcmp(lbuf, "Y")))
569 		return 1;
570 	else
571 		return 0;
572 }
573 
574 decimal(str, num, deflt)
575 char *str;
576 int *num;
577 {
578 int acc = 0, c;
579 char *cp;
580 
581 	while (1) {
582 		printf("Supply a decimal value for \"%s\" [%d] ", str, deflt);
583 		fgets(lbuf, LBUF, stdin);
584 		lbuf[strlen(lbuf)-1] = 0;
585 
586 		if (!*lbuf)
587 			return 0;
588 
589 		cp = lbuf;
590 		while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
591 		if (!c)
592 			return 0;
593 		while (c = *cp++) {
594 			if (c <= '9' && c >= '0')
595 				acc = acc * 10 + c - '0';
596 			else
597 				break;
598 		}
599 		if (c == ' ' || c == '\t')
600 			while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
601 		if (!c) {
602 			*num = acc;
603 			return 1;
604 		} else
605 			printf("%s is an invalid decimal number.  Try again\n",
606 				lbuf);
607 	}
608 
609 }
610 
611 hex(str, num, deflt)
612 char *str;
613 int *num;
614 {
615 int acc = 0, c;
616 char *cp;
617 
618 	while (1) {
619 		printf("Supply a hex value for \"%s\" [%x] ", str, deflt);
620 		fgets(lbuf, LBUF, stdin);
621 		lbuf[strlen(lbuf)-1] = 0;
622 
623 		if (!*lbuf)
624 			return 0;
625 
626 		cp = lbuf;
627 		while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
628 		if (!c)
629 			return 0;
630 		while (c = *cp++) {
631 			if (c <= '9' && c >= '0')
632 				acc = (acc << 4) + c - '0';
633 			else if (c <= 'f' && c >= 'a')
634 				acc = (acc << 4) + c - 'a' + 10;
635 			else if (c <= 'F' && c >= 'A')
636 				acc = (acc << 4) + c - 'A' + 10;
637 			else
638 				break;
639 		}
640 		if (c == ' ' || c == '\t')
641 			while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
642 		if (!c) {
643 			*num = acc;
644 			return 1;
645 		} else
646 			printf("%s is an invalid hex number.  Try again\n",
647 				lbuf);
648 	}
649 
650 }
651 
652 string(str, ans)
653 char *str;
654 char **ans;
655 {
656 int c;
657 char *cp = lbuf;
658 
659 	while (1) {
660 		printf("Supply a string value for \"%s\" [%s] ", str, *ans);
661 		fgets(lbuf, LBUF, stdin);
662 		lbuf[strlen(lbuf)-1] = 0;
663 
664 		if (!*lbuf)
665 			return 0;
666 
667 		while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
668 		if (c == '"') {
669 			c = *++cp;
670 			*ans = cp;
671 			while ((c = *cp) && c != '"') cp++;
672 		} else {
673 			*ans = cp;
674 			while ((c = *cp) && c != ' ' && c != '\t') cp++;
675 		}
676 
677 		if (c)
678 			*cp = 0;
679 		return 1;
680 	}
681 }
682 
683 char *get_type(type)
684 int	type;
685 {
686 	int	numentries = (sizeof(part_types)/sizeof(struct part_type));
687 	int	counter = 0;
688 	struct	part_type *ptr = part_types;
689 
690 
691 	while(counter < numentries)
692 	{
693 		if(ptr->type == type)
694 		{
695 			return(ptr->name);
696 		}
697 		ptr++;
698 		counter++;
699 	}
700 	return("unknown");
701 }
702