1 /* $NetBSD: interact.c,v 1.32 2009/10/21 01:07:46 snj Exp $ */
4 * Copyright (c) 1997 Christos Zoulas. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #if HAVE_NBTOOL_CONFIG_H
28 #include "nbtool_config.h"
31 #include <sys/cdefs.h>
33 __RCSID("$NetBSD: interact.c,v 1.32 2009/10/21 01:07:46 snj Exp $");
36 #include <sys/param.h>
45 #if HAVE_NBTOOL_CONFIG_H
46 #define getmaxpartitions() MAXPARTITIONS
47 #include <nbinclude/sys/disklabel.h>
50 #include <sys/disklabel.h>
51 #endif /* HAVE_NBTOOL_CONFIG_H */
55 static void cmd_help(struct disklabel
*, char *, int);
56 static void cmd_chain(struct disklabel
*, char *, int);
57 static void cmd_print(struct disklabel
*, char *, int);
58 static void cmd_printall(struct disklabel
*, char *, int);
59 static void cmd_info(struct disklabel
*, char *, int);
60 static void cmd_part(struct disklabel
*, char *, int);
61 static void cmd_label(struct disklabel
*, char *, int);
62 static void cmd_round(struct disklabel
*, char *, int);
63 static void cmd_name(struct disklabel
*, char *, int);
64 static void cmd_listfstypes(struct disklabel
*, char *, int);
65 static int runcmd(struct disklabel
*, char *, int);
66 static int getinput(const char *, const char *, const char *, char *);
67 static int alphacmp(const void *, const void *);
68 static void defnum(struct disklabel
*, char *, uint32_t);
69 static void dumpnames(const char *, const char * const *, size_t);
70 static int getnum(struct disklabel
*, char *, int);
72 static int rounding
= 0; /* sector rounding */
73 static int chaining
= 0; /* make partitions contiguous */
77 void (*func
)(struct disklabel
*, char *, int);
80 { "?", cmd_help
, "print this menu" },
81 { "C", cmd_chain
, "make partitions contiguous" },
82 { "E", cmd_printall
, "print disk label and current partition table"},
83 { "I", cmd_info
, "change label information" },
84 { "L", cmd_listfstypes
,"list all known file system types" },
85 { "N", cmd_name
, "name the label" },
86 { "P", cmd_print
, "print current partition table" },
87 { "Q", NULL
, "quit" },
88 { "R", cmd_round
, "rounding (c)ylinders (s)ectors" },
89 { "W", cmd_label
, "write the current partition table" },
96 cmd_help(struct disklabel
*lp
, char *s
, int fd
)
100 for (cmd
= cmds
; cmd
->name
!= NULL
; cmd
++)
101 printf("%s\t%s\n", cmd
->name
, cmd
->help
);
102 printf("[a-%c]\tdefine named partition\n",
103 'a' + getmaxpartitions() - 1);
108 cmd_chain(struct disklabel
*lp
, char *s
, int fd
)
113 i
= getinput(":", "Automatically adjust partitions",
114 chaining
? "yes" : "no", line
);
126 printf("Invalid answer\n");
133 cmd_printall(struct disklabel
*lp
, char *s
, int fd
)
136 showinfo(stdout
, lp
, specname
);
137 showpartitions(stdout
, lp
, Cflag
);
142 cmd_print(struct disklabel
*lp
, char *s
, int fd
)
145 showpartitions(stdout
, lp
, Cflag
);
150 cmd_info(struct disklabel
*lp
, char *s
, int fd
)
157 printf("# Current values:\n");
158 showinfo(stdout
, lp
, specname
);
163 if (i
< 0 || i
>= DKMAXTYPES
)
165 snprintf(def
, sizeof(def
), "%s", dktypenames
[i
]);
166 i
= getinput(":", "Disk type [?]", def
, line
);
171 if (!strcmp(line
, "?")) {
172 dumpnames("Supported disk types", dktypenames
,
176 for (i
= 0; i
< DKMAXTYPES
; i
++) {
177 if (!strcasecmp(dktypenames
[i
], line
)) {
183 if ((unsigned)v
>= DKMAXTYPES
) {
184 warnx("Unknown disk type: %s", line
);
193 snprintf(def
, sizeof(def
), "%.*s",
194 (int) sizeof(lp
->d_typename
), lp
->d_typename
);
195 i
= getinput(":", "Disk name", def
, line
);
199 (void) strncpy(lp
->d_typename
, line
, sizeof(lp
->d_typename
));
206 snprintf(def
, sizeof(def
), "%u", lp
->d_npartitions
);
207 i
= getinput(":", "Number of partitions", def
, line
);
212 if (sscanf(line
, "%u", &u
) != 1) {
213 printf("Invalid number of partitions `%s'\n", line
);
216 lp
->d_npartitions
= u
;
222 snprintf(def
, sizeof(def
), "%u", lp
->d_secsize
);
223 i
= getinput(":", "Sector size (bytes)", def
, line
);
228 if (sscanf(line
, "%u", &u
) != 1) {
229 printf("Invalid sector size `%s'\n", line
);
238 snprintf(def
, sizeof(def
), "%u", lp
->d_nsectors
);
239 i
= getinput(":", "Number of sectors per track", def
, line
);
244 if (sscanf(line
, "%u", &u
) != 1) {
245 printf("Invalid number of sectors `%s'\n", line
);
254 snprintf(def
, sizeof(def
), "%u", lp
->d_ntracks
);
255 i
= getinput(":", "Number of tracks per cylinder", def
, line
);
260 if (sscanf(line
, "%u", &u
) != 1) {
261 printf("Invalid number of tracks `%s'\n", line
);
270 snprintf(def
, sizeof(def
), "%u", lp
->d_secpercyl
);
271 i
= getinput(":", "Number of sectors/cylinder", def
, line
);
276 if (sscanf(line
, "%u", &u
) != 1) {
277 printf("Invalid number of sector/cylinder `%s'\n",
287 snprintf(def
, sizeof(def
), "%u", lp
->d_ncylinders
);
288 i
= getinput(":", "Total number of cylinders", def
, line
);
293 if (sscanf(line
, "%u", &u
) != 1) {
294 printf("Invalid sector size `%s'\n", line
);
297 lp
->d_ncylinders
= u
;
303 snprintf(def
, sizeof(def
), "%u", lp
->d_secperunit
);
304 i
= getinput(":", "Total number of sectors", def
, line
);
309 if (sscanf(line
, "%u", &u
) != 1) {
310 printf("Invalid number of sectors `%s'\n", line
);
313 lp
->d_secperunit
= u
;
321 snprintf(def
, sizeof(def
), "%u", lp
->d_interleave
);
322 i
= getinput(":", "Hardware sectors interleave", def
, line
);
327 if (sscanf(line
, "%u", &u
) != 1) {
328 printf("Invalid sector interleave `%s'\n", line
);
331 lp
->d_interleave
= u
;
337 snprintf(def
, sizeof(def
), "%u", lp
->d_trackskew
);
338 i
= getinput(":", "Sector 0 skew, per track", def
, line
);
343 if (sscanf(line
, "%u", &u
) != 1) {
344 printf("Invalid track sector skew `%s'\n", line
);
353 snprintf(def
, sizeof(def
), "%u", lp
->d_cylskew
);
354 i
= getinput(":", "Sector 0 skew, per cylinder", def
, line
);
359 if (sscanf(line
, "%u", &u
) != 1) {
360 printf("Invalid cylinder sector `%s'\n", line
);
369 snprintf(def
, sizeof(def
), "%u", lp
->d_headswitch
);
370 i
= getinput(":", "Head switch time (usec)", def
, line
);
375 if (sscanf(line
, "%u", &u
) != 1) {
376 printf("Invalid head switch time `%s'\n", line
);
379 lp
->d_headswitch
= u
;
385 snprintf(def
, sizeof(def
), "%u", lp
->d_trkseek
);
386 i
= getinput(":", "Track seek time (usec)", def
, line
);
391 if (sscanf(line
, "%u", &u
) != 1) {
392 printf("Invalid track seek time `%s'\n", line
);
402 cmd_name(struct disklabel
*lp
, char *s
, int fd
)
408 snprintf(def
, sizeof(def
), "%.*s",
409 (int) sizeof(lp
->d_packname
), lp
->d_packname
);
410 i
= getinput(":", "Label name", def
, line
);
413 (void) strncpy(lp
->d_packname
, line
, sizeof(lp
->d_packname
));
418 cmd_round(struct disklabel
*lp
, char *s
, int fd
)
423 i
= getinput(":", "Rounding", rounding
? "cylinders" : "sectors", line
);
437 printf("Rounding can be (c)ylinders or (s)ectors\n");
444 cmd_part(struct disklabel
*lp
, char *s
, int fd
)
450 struct partition
*p
, ps
;
453 p
= &lp
->d_partitions
[part
];
454 if (part
>= lp
->d_npartitions
)
455 lp
->d_npartitions
= part
+ 1;
457 (void)memcpy(&ps
, p
, sizeof(ps
));
461 if (i
< 0 || i
>= FSMAXTYPES
)
463 snprintf(def
, sizeof(def
), "%s", fstypenames
[i
]);
464 i
= getinput(":", "Filesystem type [?]", def
, line
);
469 if (!strcmp(line
, "?")) {
470 dumpnames("Supported file system types",
471 fstypenames
, FSMAXTYPES
);
474 for (i
= 0; i
< FSMAXTYPES
; i
++)
475 if (!strcasecmp(line
, fstypenames
[i
])) {
479 printf("Invalid file system typename `%s'\n", line
);
485 defnum(lp
, def
, p
->p_offset
);
487 "Start offset ('x' to start after partition 'x')",
493 if (line
[1] == '\0' &&
494 line
[0] >= 'a' && line
[0] < 'a' + getmaxpartitions()) {
495 struct partition
*cp
= lp
->d_partitions
;
497 if ((cp
[line
[0] - 'a'].p_offset
+
498 cp
[line
[0] - 'a'].p_size
) >= lp
->d_secperunit
) {
499 printf("Bad offset `%s'\n", line
);
502 p
->p_offset
= cp
[line
[0] - 'a'].p_offset
+
503 cp
[line
[0] - 'a'].p_size
;
506 if ((i
= getnum(lp
, line
, 0)) == -1 || i
< 0) {
507 printf("Bad offset `%s'\n", line
);
509 } else if ((uint32_t)i
> lp
->d_secperunit
) {
510 printf("Offset `%s' out of range\n", line
);
518 defnum(lp
, def
, p
->p_size
);
519 i
= getinput(":", "Partition size ('$' for all remaining)",
525 if ((i
= getnum(lp
, line
, lp
->d_secperunit
- p
->p_offset
))
527 printf("Bad size `%s'\n", line
);
530 ((i
+ p
->p_offset
) > lp
->d_secperunit
) {
531 printf("Size `%s' out of range\n", line
);
538 if (memcmp(&ps
, p
, sizeof(ps
)))
539 showpartition(stdout
, lp
, part
, Cflag
);
542 struct partition
*cp
= lp
->d_partitions
;
543 for (i
= 0; i
< lp
->d_npartitions
; i
++) {
544 if (cp
[i
].p_fstype
!= FS_UNUSED
) {
545 if (offs
!= -1 && cp
[i
].p_offset
!= (uint32_t)offs
) {
546 cp
[i
].p_offset
= offs
;
547 showpartition(stdout
, lp
, i
, Cflag
);
549 offs
= cp
[i
].p_offset
+ cp
[i
].p_size
;
557 cmd_label(struct disklabel
*lp
, char *s
, int fd
)
562 i
= getinput("?", "Label disk", "n", line
);
563 if (i
<= 0 || (*line
!= 'y' && *line
!= 'Y') )
566 if (checklabel(lp
) != 0) {
567 printf("Label not written\n");
571 if (writelabel(fd
, lp
) != 0) {
572 printf("Label not written\n");
575 printf("Label written\n");
580 cmd_listfstypes(struct disklabel
*lp
, char *s
, int fd
)
583 (void)list_fs_types();
588 runcmd(struct disklabel
*lp
, char *line
, int fd
)
592 for (cmd
= cmds
; cmd
->name
!= NULL
; cmd
++)
593 if (strncmp(line
, cmd
->name
, strlen(cmd
->name
)) == 0) {
594 if (cmd
->func
== NULL
)
596 (*cmd
->func
)(lp
, line
, fd
);
600 if (line
[1] == '\0' &&
601 line
[0] >= 'a' && line
[0] < 'a' + getmaxpartitions()) {
602 cmd_part(lp
, line
, fd
);
606 printf("Unknown command %s\n", line
);
612 getinput(const char *sep
, const char *prompt
, const char *def
, char *line
)
616 printf("%s", prompt
);
618 printf(" [%s]", def
);
621 if (fgets(line
, BUFSIZ
, stdin
) == NULL
)
623 if (line
[0] == '\n' || line
[0] == '\0') {
630 if ((p
= strrchr(line
, '\n')) != NULL
)
638 alphacmp(const void *a
, const void *b
)
641 return (strcasecmp(*(const char * const*)a
, *(const char * const*)b
));
646 dumpnames(const char *prompt
, const char * const *olist
, size_t numentries
)
649 size_t i
, entry
, lines
;
654 if ((list
= (const char **)malloc(sizeof(char *) * numentries
)) == NULL
)
657 printf("%s:\n", prompt
);
658 for (i
= 0; i
< numentries
; i
++) {
665 for (i
= 0; i
< numentries
; i
++)
666 printf("%s%s", i
== 0 ? "" : ", ", list
[i
]);
669 (void)qsort(list
, numentries
, sizeof(char *), alphacmp
);
670 width
++; /* want two spaces between items */
671 width
= (width
+ 8) &~ 7;
674 columns
= ttywidth
/ width
;
678 lines
= (numentries
+ columns
- 1) / columns
;
679 /* Output sorted by columns */
680 for (i
= 0; i
< lines
; i
++) {
687 if (entry
>= numentries
)
702 defnum(struct disklabel
*lp
, char *buf
, uint32_t size
)
705 (void) snprintf(buf
, BUFSIZ
, "%.40gc, %us, %.40gM",
706 size
/ (float) lp
->d_secpercyl
,
707 size
, size
* (lp
->d_secsize
/ (float) (1024 * 1024)));
712 getnum(struct disklabel
*lp
, char *buf
, int max
)
718 if (max
&& buf
[0] == '$' && buf
[1] == 0)
721 d
= strtod(buf
, &ep
);
725 #define ROUND(a) ((((a) / lp->d_secpercyl) + \
726 (((a) % lp->d_secpercyl) ? 1 : 0)) * lp->d_secpercyl)
737 rv
= (int) (d
* lp
->d_secpercyl
);
742 rv
= (int) (d
* 1024 / lp
->d_secsize
);
747 rv
= (int) (d
* 1024 * 1024 / lp
->d_secsize
);
752 rv
= (int) (d
* 1024 * 1024 * 1024 / lp
->d_secsize
);
757 rv
= (int) (d
* 1024 * 1024 * 1024 * 1024 / lp
->d_secsize
);
761 printf("Unit error %c\n", *ep
);
762 printf("Valid units: (S)ectors, (C)ylinders, (K)ilo, (M)ega, "
775 interact(struct disklabel
*lp
, int fd
)
779 puts("Enter '?' for help");
781 if (getinput(">", "partition", NULL
, line
) == -1)
783 if (runcmd(lp
, line
, fd
) == -1)