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