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