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