interact.c revision 1.11 1 /* $NetBSD: interact.c,v 1.11 1999/11/26 06:03:10 mrg Exp $ */
2
3 /*
4 * Copyright (c) 1997 Christos Zoulas. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by Christos Zoulas.
17 * 4. The name of the author may not be used to endorse or promote products
18 * derived from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 #ifndef lint
34 __RCSID("$NetBSD: interact.c,v 1.11 1999/11/26 06:03:10 mrg Exp $");
35 #endif /* lint */
36
37 #include <sys/param.h>
38 #define FSTYPENAMES
39 #define DKTYPENAMES
40 #include <sys/disklabel.h>
41
42 #include <err.h>
43 #include <stdio.h>
44 #include <string.h>
45 #include <stdlib.h>
46 #include <util.h>
47
48 #include "extern.h"
49
50 static void cmd_help __P((struct disklabel *, char *, int));
51 static void cmd_chain __P((struct disklabel *, char *, int));
52 static void cmd_print __P((struct disklabel *, char *, int));
53 static void cmd_printall __P((struct disklabel *, char *, int));
54 static void cmd_info __P((struct disklabel *, char *, int));
55 static void cmd_part __P((struct disklabel *, char *, int));
56 static void cmd_label __P((struct disklabel *, char *, int));
57 static void cmd_round __P((struct disklabel *, char *, int));
58 static void cmd_name __P((struct disklabel *, char *, int));
59 static int runcmd __P((char *, struct disklabel *, int));
60 static int getinput __P((const char *, const char *, const char *, char *));
61 static void defnum __P((char *, struct disklabel *, int));
62 static int getnum __P((char *, struct disklabel *));
63 static void deffstypename __P((char *, int));
64 static int getfstypename __P((const char *));
65
66 static int rounding = 0; /* sector rounding */
67 static int chaining = 0; /* make partitions contiguous */
68
69 static struct cmds {
70 const char *name;
71 void (*func) __P((struct disklabel *, char *, int));
72 const char *help;
73 } cmds[] = {
74 { "?", cmd_help, "print this menu" },
75 { "C", cmd_chain, "make partitions contiguous" },
76 { "E", cmd_printall, "print disk label and current partition table"},
77 { "I", cmd_info, "change label information" },
78 { "N", cmd_name, "name the label" },
79 { "P", cmd_print, "print current partition table" },
80 { "Q", NULL, "quit" },
81 { "R", cmd_round, "rounding (c)ylinders (s)ectors" },
82 { "W", cmd_label, "write the current partition table" },
83 { NULL, NULL, NULL }
84 };
85
86
87
88 static void
89 cmd_help(lp, s, fd)
90 struct disklabel *lp;
91 char *s;
92 int fd;
93 {
94 struct cmds *cmd;
95
96 for (cmd = cmds; cmd->name != NULL; cmd++)
97 printf("%s\t%s\n", cmd->name, cmd->help);
98 printf("[a-%c]\tdefine named partition\n",
99 'a' + getmaxpartitions() - 1);
100 }
101
102
103 static void
104 cmd_chain(lp, s, fd)
105 struct disklabel *lp;
106 char *s;
107 int fd;
108 {
109 int i;
110 char line[BUFSIZ];
111
112 i = getinput(":", "Automatically adjust partitions",
113 chaining ? "yes" : "no", line);
114
115 if (i <= 0)
116 return;
117
118 switch (line[0]) {
119 case 'y':
120 chaining = 1;
121 return;
122 case 'n':
123 chaining = 0;
124 return;
125 default:
126 printf("Invalid answer\n");
127 return;
128 }
129 }
130
131 static void
132 cmd_printall(lp, s, fd)
133 struct disklabel *lp;
134 char *s;
135 int fd;
136 {
137
138 showinfo(stdout, lp);
139 showpartitions(stdout, lp);
140 }
141
142 static void
143 cmd_print(lp, s, fd)
144 struct disklabel *lp;
145 char *s;
146 int fd;
147 {
148 showpartitions(stdout, lp);
149 }
150
151 static void
152 cmd_info(lp, s, fd)
153 struct disklabel *lp;
154 char *s;
155 int fd;
156 {
157 char line[BUFSIZ];
158 char def[BUFSIZ];
159 const char * const *cpp;
160 const char *t;
161 int v, i;
162 u_int32_t u;
163
164 printf("# Current values:\n");
165 showinfo(stdout, lp);
166
167 /* d_typename */
168 for (;;) {
169 strncpy(def, lp->d_typename, sizeof(def));
170 def[sizeof(def) - 1] = '\0';
171 i = getinput(":", "Disk type", def, line);
172 if (i <= 0)
173 break;
174 cpp = dktypenames;
175 for (; cpp < &dktypenames[DKMAXTYPES]; cpp++)
176 if ((t = *cpp) && !strcmp(t, line)) {
177 lp->d_type = cpp - dktypenames;
178 goto done_typename;
179 }
180 v = atoi(line);
181 if ((unsigned)v >= DKMAXTYPES) {
182 warnx("unknown disk type: %s", line);
183 continue;
184 }
185 lp->d_type = v;
186 done_typename:
187 break;
188 }
189
190 /* d_packname */
191 cmd_name(lp, s, fd);
192
193 /* d_npartitions */
194 for (;;) {
195 snprintf(def, sizeof def, "%u", lp->d_npartitions);
196 i = getinput(":", "Number of partitions", def, line);
197 if (i <= 0)
198 break;
199 if (sscanf(line, "%u", &u) != 1) {
200 printf("Invalid sector size `%s'\n", line);
201 continue;
202 }
203 lp->d_npartitions = u;
204 break;
205 }
206
207 /* d_secsize */
208 for (;;) {
209 snprintf(def, sizeof def, "%u", lp->d_secsize);
210 i = getinput(":", "Sector size (bytes)", def, line);
211 if (i <= 0)
212 break;
213 if (sscanf(line, "%u", &u) != 1) {
214 printf("Invalid sector size `%s'\n", line);
215 continue;
216 }
217 lp->d_secsize = u;
218 break;
219 }
220
221 /* d_nsectors */
222 for (;;) {
223 snprintf(def, sizeof def, "%u", lp->d_nsectors);
224 i = getinput(":", "Number of sectors per track", def, line);
225 if (i <= 0)
226 break;
227 if (sscanf(line, "%u", &u) != 1) {
228 printf("Invalid number of sector `%s'\n", line);
229 continue;
230 }
231 lp->d_nsectors = u;
232 break;
233 }
234
235 /* d_ntracks */
236 for (;;) {
237 snprintf(def, sizeof def, "%u", lp->d_ntracks);
238 i = getinput(":", "Number of tracks per cylinder", def, line);
239 if (i <= 0)
240 break;
241 if (sscanf(line, "%u", &u) != 1) {
242 printf("Invalid number of tracks `%s'\n", line);
243 continue;
244 }
245 lp->d_ntracks = u;
246 break;
247 }
248
249 /* d_secpercyl */
250 for (;;) {
251 snprintf(def, sizeof def, "%u", lp->d_secpercyl);
252 i = getinput(":", "Number of sectors/cylinder", def, line);
253 if (i <= 0)
254 break;
255 if (sscanf(line, "%u", &u) != 1) {
256 printf("Invalid number of sector/cylinder `%s'\n", line);
257 continue;
258 }
259 lp->d_secpercyl = u;
260 break;
261 }
262
263 /* d_ncylinders */
264 for (;;) {
265 snprintf(def, sizeof def, "%u", lp->d_ncylinders);
266 i = getinput(":", "Total number of cylinders", def, line);
267 if (i <= 0)
268 break;
269 if (sscanf(line, "%u", &u) != 1) {
270 printf("Invalid sector size `%s'\n", line);
271 continue;
272 }
273 lp->d_ncylinders = u;
274 break;
275 }
276
277 /* d_secperunit */
278 for (;;) {
279 snprintf(def, sizeof def, "%u", lp->d_secperunit);
280 i = getinput(":", "Total number of sectors", def, line);
281 if (i <= 0)
282 break;
283 if (sscanf(line, "%u", &u) != 1) {
284 printf("Invalid number of sector `%s'\n", line);
285 continue;
286 }
287 lp->d_secperunit = u;
288 break;
289 }
290
291 /* d_rpm */
292
293 /* d_interleave */
294 for (;;) {
295 snprintf(def, sizeof def, "%u", lp->d_interleave);
296 i = getinput(":", "Hardware sectors interleave", def, line);
297
298 if (i <= 0)
299 break;
300 if (sscanf(line, "%u", &u) != 1) {
301 printf("Invalid sector size `%s'\n", line);
302 continue;
303 }
304 lp->d_interleave = u;
305 break;
306 }
307
308 /* d_trackskew */
309 for (;;) {
310 snprintf(def, sizeof def, "%u", lp->d_trackskew);
311 i = getinput(":", "Sector 0 skew, per track", def, line);
312 if (i <= 0)
313 break;
314 if (sscanf(line, "%u", &u) != 1) {
315 printf("Invalid sector size `%s'\n", line);
316 continue;
317 }
318 lp->d_trackskew = u;
319 break;
320 }
321
322 /* d_cylskew */
323 for (;;) {
324 snprintf(def, sizeof def, "%u", lp->d_cylskew);
325 i = getinput(":", "Sector 0 skew, per cylinder", def, line);
326 if (i <= 0)
327 break;
328 if (sscanf(line, "%u", &u) != 1) {
329 printf("Invalid sector size `%s'\n", line);
330 continue;
331 }
332 lp->d_cylskew = u;
333 break;
334 }
335
336 /* d_headswitch */
337 for (;;) {
338 snprintf(def, sizeof def, "%u", lp->d_headswitch);
339 i = getinput(":", "Head switch time (usec)", def, line);
340 if (i <= 0)
341 break;
342 if (sscanf(line, "%u", &u) != 1) {
343 printf("Invalid sector size `%s'\n", line);
344 continue;
345 }
346 lp->d_headswitch = u;
347 break;
348 }
349
350 /* d_trkseek */
351 for (;;) {
352 snprintf(def, sizeof def, "%u", lp->d_trkseek);
353 i = getinput(":", "Track seek time (usec)", def, line);
354 if (i <= 0)
355 break;
356 if (sscanf(line, "%u", &u) != 1) {
357 printf("Invalid sector size `%s'\n", line);
358 continue;
359 }
360 lp->d_trkseek = u;
361 break;
362 }
363
364 }
365
366 static void
367 cmd_name(lp, s, fd)
368 struct disklabel *lp;
369 char *s;
370 int fd;
371 {
372 char line[BUFSIZ];
373 int i = getinput(":", "Label name", lp->d_packname, line);
374
375 if (i <= 0)
376 return;
377 (void) strncpy(lp->d_packname, line, sizeof(lp->d_packname));
378 }
379
380 static void
381 cmd_round(lp, s, fd)
382 struct disklabel *lp;
383 char *s;
384 int fd;
385 {
386 int i;
387 char line[BUFSIZ];
388
389 i = getinput(":", "Rounding", rounding ? "cylinders" : "sectors", line);
390
391 if (i <= 0)
392 return;
393
394 switch (line[0]) {
395 case 'c':
396 rounding = 1;
397 return;
398 case 's':
399 rounding = 0;
400 return;
401 default:
402 printf("Rounding can be (c)ylinders or (s)ectors\n");
403 return;
404 }
405 }
406
407 static void
408 cmd_part(lp, s, fd)
409 struct disklabel *lp;
410 char *s;
411 int fd;
412 {
413 int i;
414 char line[BUFSIZ];
415 char def[BUFSIZ];
416 int part = *s - 'a';
417 struct partition *p = &lp->d_partitions[part];
418
419 if (part >= lp->d_npartitions)
420 lp->d_npartitions = part + 1;
421
422 for (;;) {
423 deffstypename(def, p->p_fstype);
424 i = getinput(":", "Filesystem type", def, line);
425 if (i <= 0)
426 break;
427 if ((i = getfstypename(line)) == -1) {
428 printf("Invalid file system typename `%s'\n", line);
429 continue;
430 }
431 p->p_fstype = i;
432 break;
433 }
434 for (;;) {
435 defnum(def, lp, p->p_offset);
436 i = getinput(":", "Start offset", def, line);
437 if (i <= 0)
438 break;
439 if ((i = getnum(line, lp)) == -1) {
440 printf("Bad offset `%s'\n", line);
441 continue;
442 }
443 p->p_offset = i;
444 break;
445 }
446 for (;;) {
447 defnum(def, lp, p->p_size);
448 i = getinput(":", "Partition size", def, line);
449 if (i <= 0)
450 break;
451 if ((i = getnum(line, lp)) == -1) {
452 printf("Bad size `%s'\n", line);
453 continue;
454 }
455 p->p_size = i;
456 break;
457 }
458
459 if (chaining) {
460 int offs = p[0].p_offset + p[0].p_size;
461 p = lp->d_partitions;
462 part = getrawpartition();
463 for (i = 1; i < lp->d_npartitions; i++) {
464 if (i != part && p[i].p_fstype) {
465 p[i].p_offset = offs;
466 offs = p[i].p_offset + p[i].p_size;
467 }
468 }
469 }
470 }
471
472
473 static void
474 cmd_label(lp, s, fd)
475 struct disklabel *lp;
476 char *s;
477 int fd;
478 {
479 char line[BUFSIZ];
480 int i;
481
482 i = getinput("?", "Label disk", "n", line);
483
484 if (i <= 0 || (*line != 'y' && *line != 'Y') )
485 return;
486
487 if (checklabel(lp) != 0) {
488 printf("Label not written\n");
489 return;
490 }
491
492 if (writelabel(fd, bootarea, lp) != 0) {
493 printf("Label not written\n");
494 return;
495 }
496 printf("Label written\n");
497 }
498
499
500 static int
501 runcmd(line, lp, fd)
502 char *line;
503 struct disklabel *lp;
504 int fd;
505 {
506 struct cmds *cmd;
507
508 for (cmd = cmds; cmd->name != NULL; cmd++)
509 if (strncmp(line, cmd->name, strlen(cmd->name)) == 0) {
510 if (cmd->func == NULL)
511 return -1;
512 (*cmd->func)(lp, line, fd);
513 return 0;
514 }
515
516 if (line[1] == '\0' &&
517 line[0] >= 'a' && line[0] < 'a' + getmaxpartitions()) {
518 cmd_part(lp, line, fd);
519 return 0;
520 }
521
522 printf("Unknown command %s\n", line);
523 return 1;
524 }
525
526
527 static int
528 getinput(sep, prompt, def, line)
529 const char *sep;
530 const char *prompt;
531 const char *def;
532 char *line;
533 {
534 for (;;) {
535 printf("%s", prompt);
536 if (def)
537 printf(" [%s]", def);
538 printf("%s ", sep);
539
540 if (fgets(line, BUFSIZ, stdin) == NULL)
541 return -1;
542 if (line[0] == '\n' || line[0] == '\0') {
543 if (def)
544 return 0;
545 }
546 else {
547 char *p;
548
549 if ((p = strrchr(line, '\n')) != NULL)
550 *p = '\0';
551 return 1;
552 }
553 }
554 }
555
556
557 static void
558 defnum(buf, lp, size)
559 char *buf;
560 struct disklabel *lp;
561 int size;
562 {
563 (void) snprintf(buf, BUFSIZ, "%gc, %ds, %gM",
564 size / (float) lp->d_secpercyl,
565 size, size * (lp->d_secsize / (float) (1024 * 1024)));
566 }
567
568
569 static int
570 getnum(buf, lp)
571 char *buf;
572 struct disklabel *lp;
573 {
574 char *ep;
575 double d = strtod(buf, &ep);
576 int rv;
577
578 if (buf == ep)
579 return -1;
580
581 #define ROUND(a) ((a / lp->d_secpercyl) + \
582 ((a % lp->d_secpercyl) ? 1 : 0)) * lp->d_secpercyl
583
584 switch (*ep) {
585 case '\0':
586 case 's':
587 rv = (int) d;
588 break;
589
590 case 'c':
591 rv = (int) (d * lp->d_secpercyl);
592 break;
593
594 case 'M':
595 rv = (int) (d * 1024 * 1024 / lp->d_secsize);
596 break;
597
598 default:
599 printf("Unit error %c\n", *ep);
600 return -1;
601 }
602
603 if (rounding)
604 return ROUND(rv);
605 else
606 return rv;
607 }
608
609
610 static void
611 deffstypename(buf, i)
612 char *buf;
613 int i;
614 {
615 if (i < 0 || i >= FSMAXTYPES)
616 i = 0;
617 (void) strcpy(buf, fstypenames[i]);
618 }
619
620
621 static int
622 getfstypename(buf)
623 const char *buf;
624 {
625 int i;
626
627 for (i = 0; i < FSMAXTYPES; i++)
628 if (strcmp(buf, fstypenames[i]) == 0)
629 return i;
630 return -1;
631 }
632
633
634 void
635 interact(lp, fd)
636 struct disklabel *lp;
637 int fd;
638 {
639 char line[BUFSIZ];
640
641 for (;;) {
642 if (getinput(">", "partition", NULL, line) == -1)
643 return;
644 if (runcmd(line, lp, fd) == -1)
645 return;
646 }
647 }
648