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