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