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