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