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