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