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