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