fdisk.c revision 3723
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	partp[active].dp_flag = ACTIVE;
401}
402
403get_params_to_use()
404{
405	int	tmp;
406	print_params();
407	if (ok("Do you want to change our idea of what BIOS thinks ?"))
408	{
409		do
410		{
411			Decimal("BIOS's idea of #cylinders", dos_cyls, tmp);
412			Decimal("BIOS's idea of #heads", dos_heads, tmp);
413			Decimal("BIOS's idea of #sectors", dos_sectors, tmp);
414			dos_cylsecs = dos_heads * dos_sectors;
415			print_params();
416		}
417		while(!ok("Are you happy with this choice"));
418	}
419}
420
421/***********************************************\
422* Change real numbers into strange dos numbers	*
423\***********************************************/
424static
425dos(sec, c, s, h)
426int sec;
427unsigned char *c, *s, *h;
428{
429int cy;
430int hd;
431
432	if (sec == 0) {
433		*s = *c = *h = 0;
434		return;
435	}
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
448int fd;
449
450	/* Getting device status */
451
452open_disk(u_flag)
453{
454struct 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	}
461	if ( !(st.st_mode & S_IFCHR) )
462		fprintf(stderr,"%s: Device %s is not character special\n",
463			name, disk);
464	if ((fd = open(disk, a_flag || u_flag ? O_RDWR : O_RDONLY)) == -1) {
465		fprintf(stderr,"%s: Can't open device %s\n", name, disk);
466		return -1;
467	}
468	if (get_params(0) == -1) {
469		fprintf(stderr, "%s: Can't get disk parameters on %s\n",
470			name, disk);
471		return -1;
472	}
473	return fd;
474}
475
476
477read_disk(sector, buf)
478{
479	lseek(fd,(sector * 512), 0);
480	return read(fd, buf, 512);
481}
482
483write_disk(sector, buf)
484{
485	lseek(fd,(sector * 512), 0);
486	return write(fd, buf, 512);
487}
488
489get_params(verbose)
490{
491
492    if (ioctl(fd, DIOCGDINFO, &disklabel) == -1) {
493	fprintf(stderr,
494		"%s: Can't get disk parameters on %s; supplying dummy ones\n",
495		name, disk);
496	dos_cyls = cyls = 1;
497	dos_heads = heads = 1;
498	dos_sectors = sectors = 1;
499	dos_cylsecs = cylsecs = heads * sectors;
500	disksecs = cyls * heads * sectors;
501	return disksecs;
502    }
503
504    dos_cyls = cyls = disklabel.d_ncylinders;
505    dos_heads = heads = disklabel.d_ntracks;
506    dos_sectors = sectors = disklabel.d_nsectors;
507    dos_cylsecs = cylsecs = heads * sectors;
508    disksecs = cyls * heads * sectors;
509
510    return (disksecs);
511}
512
513
514read_s0()
515{
516	if (read_disk(0, (char *) mboot.bootinst) == -1) {
517		fprintf(stderr, "%s: Can't read fdisk partition table\n", name);
518		return -1;
519	}
520	if (mboot.signature != BOOT_MAGIC) {
521		fprintf(stderr, "%s: Invalid fdisk partition table found\n",
522			name);
523		/* So should we initialize things */
524		return -1;
525	}
526	return 0;
527}
528
529write_s0()
530{
531	int	flag;
532	if (iotest) {
533		print_s0(-1);
534		return 0;
535	}
536	/*
537	 * write enable label sector before write (if necessary),
538	 * disable after writing.
539	 * needed if the disklabel protected area also protects
540	 * sector 0. (e.g. empty disk)
541	 */
542	flag = 1;
543	if (ioctl(fd, DIOCWLABEL, &flag) < 0)
544		perror("ioctl DIOCWLABEL");
545	if (write_disk(0, (char *) mboot.bootinst) == -1) {
546		fprintf(stderr, "%s: Can't write fdisk partition table\n",
547			name);
548		return -1;
549	flag = 0;
550	(void) ioctl(fd, DIOCWLABEL, &flag);
551	}
552}
553
554
555
556ok(str)
557char *str;
558{
559	printf("%s [n] ", str);
560	fgets(lbuf, LBUF, stdin);
561	lbuf[strlen(lbuf)-1] = 0;
562
563	if (*lbuf &&
564		(!strcmp(lbuf, "yes") || !strcmp(lbuf, "YES") ||
565		 !strcmp(lbuf, "y") || !strcmp(lbuf, "Y")))
566		return 1;
567	else
568		return 0;
569}
570
571decimal(str, num, deflt)
572char *str;
573int *num;
574{
575int acc = 0, c;
576char *cp;
577
578	while (1) {
579		printf("Supply a decimal value for \"%s\" [%d] ", str, deflt);
580		fgets(lbuf, LBUF, stdin);
581		lbuf[strlen(lbuf)-1] = 0;
582
583		if (!*lbuf)
584			return 0;
585
586		cp = lbuf;
587		while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
588		if (!c)
589			return 0;
590		while (c = *cp++) {
591			if (c <= '9' && c >= '0')
592				acc = acc * 10 + c - '0';
593			else
594				break;
595		}
596		if (c == ' ' || c == '\t')
597			while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
598		if (!c) {
599			*num = acc;
600			return 1;
601		} else
602			printf("%s is an invalid decimal number.  Try again\n",
603				lbuf);
604	}
605
606}
607
608hex(str, num, deflt)
609char *str;
610int *num;
611{
612int acc = 0, c;
613char *cp;
614
615	while (1) {
616		printf("Supply a hex value for \"%s\" [%x] ", str, deflt);
617		fgets(lbuf, LBUF, stdin);
618		lbuf[strlen(lbuf)-1] = 0;
619
620		if (!*lbuf)
621			return 0;
622
623		cp = lbuf;
624		while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
625		if (!c)
626			return 0;
627		while (c = *cp++) {
628			if (c <= '9' && c >= '0')
629				acc = (acc << 4) + c - '0';
630			else if (c <= 'f' && c >= 'a')
631				acc = (acc << 4) + c - 'a' + 10;
632			else if (c <= 'F' && c >= 'A')
633				acc = (acc << 4) + c - 'A' + 10;
634			else
635				break;
636		}
637		if (c == ' ' || c == '\t')
638			while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
639		if (!c) {
640			*num = acc;
641			return 1;
642		} else
643			printf("%s is an invalid hex number.  Try again\n",
644				lbuf);
645	}
646
647}
648
649string(str, ans)
650char *str;
651char **ans;
652{
653int c;
654char *cp = lbuf;
655
656	while (1) {
657		printf("Supply a string value for \"%s\" [%s] ", str, *ans);
658		fgets(lbuf, LBUF, stdin);
659		lbuf[strlen(lbuf)-1] = 0;
660
661		if (!*lbuf)
662			return 0;
663
664		while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
665		if (c == '"') {
666			c = *++cp;
667			*ans = cp;
668			while ((c = *cp) && c != '"') cp++;
669		} else {
670			*ans = cp;
671			while ((c = *cp) && c != ' ' && c != '\t') cp++;
672		}
673
674		if (c)
675			*cp = 0;
676		return 1;
677	}
678}
679
680char *get_type(type)
681int	type;
682{
683	int	numentries = (sizeof(part_types)/sizeof(struct part_type));
684	int	counter = 0;
685	struct	part_type *ptr = part_types;
686
687
688	while(counter < numentries)
689	{
690		if(ptr->type == type)
691		{
692			return(ptr->name);
693		}
694		ptr++;
695		counter++;
696	}
697	return("unknown");
698}
699