Hi, the following patches are my supposal for: * Adding a batch mode (option -s) * Adding an option to set partition alignment rather than just cylinder or sector rounding * Add option to specify percentages. This is somewhat unclear, as it will currently take d_secperunit, which won't work with mbrs. We could add some magic to check whether we have an mbr, but this won't be very clean. * Also include the 'fixes' I posted to bin/45749. Though the segfault isn't fixed yet. I still don't know if it is desirable to have mbr checks, doing some with a constant partition c, etc. Please have a look at the code and comment. Regards, Julian
--- sbin/disklabel/Makefile
+++ sbin/disklabel/Makefile
@@ -1,10 +1,10 @@
# $NetBSD: Makefile,v 1.69 2011/08/30 12:39:52 bouyer Exp $
# @(#)Makefile 8.2 (Berkeley) 3/17/94
PROG= disklabel
-SRCS= main.c dkcksum.c interact.c printlabel.c
+SRCS= main.c dkcksum.c interact.c printlabel.c batch.c
MAN= disklabel.5 disklabel.8
.if (${HOSTPROG:U} == "")
DPADD+= ${LIBUTIL}
LDADD+= -lutil
.endif
--- sbin/disklabel/disklabel.8 +++ sbin/disklabel/disklabel.8 @@ -40,20 +40,33 @@ .Nd read and write disk pack label .Sh SYNOPSIS .\" disklabel: read label .Nm .Op Fl ACDFrtv +.Op Fl s Ar num/start/size/usage Ns Bo Ar /fsize/bsize Ns Bq Ar /cpg Bc +.Op Fl p Ar param=value .Ar disk .\" disklabel -e: read/modify/write using $EDITOR .Nm .Fl e .Op Fl CDFIrv +.Op Fl s Ar num/start/size/usage Ns Bo Ar /fsize/bsize Ns Bq Ar /cpg Bc +.Op Fl p Ar param=value .Ar disk .\" disklabel -i: read/modify/write using builtin commands .Nm .Fl i .Op Fl DFIrv +.Op Fl s Ar num/start/size/usage Ns Bo Ar /fsize/bsize Ns Bq Ar /cpg Bc +.Op Fl p Ar param=value +.Ar disk +.\" disklabel -u: update without interaction +.Nm +.Fl u +.Op Fl DFIrv +.Op Fl s Ar num/start/size/usage Ns Bo Ar /fsize/bsize Ns Bq Ar /cpg Bc +.Op Fl p Ar param=value .Ar disk .\" disklabel -R: write from edited output .Nm .Fl R .Op Fl DFrv @@ -77,11 +90,11 @@ can be used to install, examine, or modify the label on a disk drive or pack. When writing the label, it can be used to change the drive identification, the disk partitions on the drive, or to replace a damaged label. .Pp The -.Fl e , i , l , R , w , N , +.Fl e , i , l , u , R , w , N , and .Fl W options determine the basic operation. If none are specified the label is displayed. @@ -98,10 +111,15 @@ .It Fl i Interactively update the existing label and write it back to the disk. .It Fl l Show all known file system types (those that can be specified along a partition within the label) and exit. +.It Fl u +Update the label without further interaction (only useful in conjunction with +.Fl s +or +.Fl p ) . .It Fl R Write (restore) a label by reading it from .Ar protofile . The file should be in the same format as the default output. .It Fl w @@ -180,10 +198,49 @@ .Fl F . .It Fl t Format the output as a .Xr disktab 5 entry. +.It Fl s Ar num/start/size/fstype Ns Bo Ar /fsize/bsize Ns Bq Ar /cpg Bc +Set partition +.Ar num , +given as a lower letter to a partition with start sector +.Ar start , +size +.Ar size +and file system type +.Ar fstype . +Overlapping partitions will be deleted. +You can set the +.Ar start +to +.Dq x +to make it start directly after partition +.Dq x . +If you specify this option when showing a label, you see the disklabel as if the +changes were applied. +.Pp +Optionally, you can also specify the fragment size with +.Ar fsize +and the block size with +.Ar bsize , +as well as additionally the number of cylinders per group (or segment shift in +case of LFS) with +.Ar cpg . +.It Fl p Ar param=value Ns Op Ns , Ns Ar param=value , Ns Ar ... +Set disklabel parameter +.Ar param +to value +.Ar value . +you can specify multiple parameters by separating them by commas. +.Pp +The names of the values are those as defined in +.Xr disklabel 5 +without the leading +.Ar d_ , +thus being +.Ar type , typename , packname , npartitions , secsize , nsectors , ntracks , secpercyl , ncylinders , secperunit , rpm , interleave , trackskew , cylskew , headswitch , trkseek . .It Fl v Be verbose about the operations being done, in particular the disk sectors being read and written. Specifying .Fl v @@ -236,10 +293,16 @@ .Dl Ic disklabel sd0 .Pp Display the in-core label for sd0 as obtained via .Pa /dev/rsd0c . .Pp +.Dl Ic disklabel -s a/1024m/2048m/unused sd0 +.Pp +Display the in-core label for sd0, but change partition +.Dq a +to start at 1024MB and be 2048MB large, deleting any overlapping partitions. +.Pp .Dl Ic disklabel -i -r sd0 .Pp Read the on-disk label for sd0, edit it using the built-in interactive editor and reinstall in-core as well as on-disk. .Pp @@ -272,10 +335,23 @@ .Pp .Dl Ic disklabel -R sd0 mylabel .Pp Restore the on-disk and in-core label for sd0 from information in .Pa mylabel . +.Pp +.Dl Ic disklabel -u -p typename=primary +.Pp +Change the disklabel's name to +.Dq primary . +.Pp +.Dl Ic disklabel -u -s a/1g/50%/4.2BSD -p typename=primary sd0 +.Pp +Change partition +.Dq a +of disk sd0 to start at 1GB from the beginning of the disklabel, take 50% of +the whole space and change the name of the disklabel to +.Dq primary . .Sh DIAGNOSTICS The kernel device drivers will not allow the size of a disk partition to be decreased or the offset of a partition to be changed while it is open. Some device drivers create a label containing only a single large partition if a disk is unlabeled; thus, the label must be written to the
--- sbin/disklabel/interact.c
+++ sbin/disklabel/interact.c
@@ -57,21 +57,19 @@
static void cmd_print(struct disklabel *, char *, int);
static void cmd_printall(struct disklabel *, char *, int);
static void cmd_info(struct disklabel *, char *, int);
static void cmd_part(struct disklabel *, char *, int);
static void cmd_label(struct disklabel *, char *, int);
-static void cmd_round(struct disklabel *, char *, int);
+static void cmd_align(struct disklabel *, char *, int);
static void cmd_name(struct disklabel *, char *, int);
static void cmd_listfstypes(struct disklabel *, char *, int);
static int runcmd(struct disklabel *, char *, int);
static int getinput(const char *, const char *, const char *, char *);
static int alphacmp(const void *, const void *);
static void defnum(struct disklabel *, char *, uint32_t);
static void dumpnames(const char *, const char * const *, size_t);
-static intmax_t getnum(struct disklabel *, char *, intmax_t);
-static int rounding = 0; /* sector rounding */
static int chaining = 0; /* make partitions contiguous */
static struct cmds {
const char *name;
void (*func)(struct disklabel *, char *, int);
@@ -83,16 +81,15 @@
{ "I", cmd_info, "change label information" },
{ "L", cmd_listfstypes,"list all known file system types" },
{ "N", cmd_name, "name the label" },
{ "P", cmd_print, "print current partition table" },
{ "Q", NULL, "quit" },
- { "R", cmd_round, "rounding (c)ylinders (s)ectors" },
+ { "A", cmd_align, "set alignment" },
{ "W", cmd_label, "write the current partition table" },
{ NULL, NULL, NULL }
};
-
-
+
static void
cmd_help(struct disklabel *lp, char *s, int fd)
{
struct cmds *cmd;
@@ -150,11 +147,12 @@
cmd_info(struct disklabel *lp, char *s, int fd)
{
char line[BUFSIZ];
char def[BUFSIZ];
int v, i;
- u_int32_t u;
+ u_int32_t u32;
+ u_int16_t u16;
printf("# Current values:\n");
showinfo(stdout, lp, specname);
/* d_type */
@@ -207,15 +205,15 @@
i = getinput(":", "Number of partitions", def, line);
if (i == -1)
return;
else if (i == 0)
break;
- if (sscanf(line, "%" SCNu32, &u) != 1) {
+ if (strtouint16(line, &u16)) {
printf("Invalid number of partitions `%s'\n", line);
continue;
}
- lp->d_npartitions = u;
+ lp->d_npartitions = u16;
break;
}
/* d_secsize */
for (;;) {
@@ -223,15 +221,15 @@
i = getinput(":", "Sector size (bytes)", def, line);
if (i == -1)
return;
else if (i == 0)
break;
- if (sscanf(line, "%" SCNu32, &u) != 1) {
+ if (strtouint32(line, &u32)) {
printf("Invalid sector size `%s'\n", line);
continue;
}
- lp->d_secsize = u;
+ lp->d_secsize = u32;
break;
}
/* d_nsectors */
for (;;) {
@@ -239,15 +237,15 @@
i = getinput(":", "Number of sectors per track", def, line);
if (i == -1)
return;
else if (i == 0)
break;
- if (sscanf(line, "%" SCNu32, &u) != 1) {
+ if (strtouint32(line, &u32)) {
printf("Invalid number of sectors `%s'\n", line);
continue;
}
- lp->d_nsectors = u;
+ lp->d_nsectors = u32;
break;
}
/* d_ntracks */
for (;;) {
@@ -255,15 +253,15 @@
i = getinput(":", "Number of tracks per cylinder", def, line);
if (i == -1)
return;
else if (i == 0)
break;
- if (sscanf(line, "%" SCNu32, &u) != 1) {
+ if (strtouint32(line, &u32)) {
printf("Invalid number of tracks `%s'\n", line);
continue;
}
- lp->d_ntracks = u;
+ lp->d_ntracks = u32;
break;
}
/* d_secpercyl */
for (;;) {
@@ -271,16 +269,16 @@
i = getinput(":", "Number of sectors/cylinder", def, line);
if (i == -1)
return;
else if (i == 0)
break;
- if (sscanf(line, "%" SCNu32, &u) != 1) {
+ if (strtouint32(line, &u32)) {
printf("Invalid number of sector/cylinder `%s'\n",
line);
continue;
}
- lp->d_secpercyl = u;
+ lp->d_secpercyl = u32;
break;
}
/* d_ncylinders */
for (;;) {
@@ -288,15 +286,15 @@
i = getinput(":", "Total number of cylinders", def, line);
if (i == -1)
return;
else if (i == 0)
break;
- if (sscanf(line, "%" SCNu32, &u) != 1) {
+ if (strtouint32(line, &u32)) {
printf("Invalid sector size `%s'\n", line);
continue;
}
- lp->d_ncylinders = u;
+ lp->d_ncylinders = u32;
break;
}
/* d_secperunit */
for (;;) {
@@ -304,15 +302,15 @@
i = getinput(":", "Total number of sectors", def, line);
if (i == -1)
return;
else if (i == 0)
break;
- if (sscanf(line, "%" SCNu32, &u) != 1) {
+ if (strtouint32(line, &u32)) {
printf("Invalid number of sectors `%s'\n", line);
continue;
}
- lp->d_secperunit = u;
+ lp->d_secperunit = u32;
break;
}
/* d_rpm */
@@ -322,15 +320,15 @@
i = getinput(":", "Hardware sectors interleave", def, line);
if (i == -1)
return;
else if (i == 0)
break;
- if (sscanf(line, "%" SCNu32, &u) != 1) {
+ if (strtouint16(line, &u16)) {
printf("Invalid sector interleave `%s'\n", line);
continue;
}
- lp->d_interleave = u;
+ lp->d_interleave = u16;
break;
}
/* d_trackskew */
for (;;) {
@@ -338,15 +336,15 @@
i = getinput(":", "Sector 0 skew, per track", def, line);
if (i == -1)
return;
else if (i == 0)
break;
- if (sscanf(line, "%" SCNu32, &u) != 1) {
+ if (strtouint16(line, &u16)) {
printf("Invalid track sector skew `%s'\n", line);
continue;
}
- lp->d_trackskew = u;
+ lp->d_trackskew = u16;
break;
}
/* d_cylskew */
for (;;) {
@@ -354,15 +352,15 @@
i = getinput(":", "Sector 0 skew, per cylinder", def, line);
if (i == -1)
return;
else if (i == 0)
break;
- if (sscanf(line, "%" SCNu32, &u) != 1) {
+ if (strtouint16(line, &u16)) {
printf("Invalid cylinder sector `%s'\n", line);
continue;
}
- lp->d_cylskew = u;
+ lp->d_cylskew = u16;
break;
}
/* d_headswitch */
for (;;) {
@@ -370,15 +368,15 @@
i = getinput(":", "Head switch time (usec)", def, line);
if (i == -1)
return;
else if (i == 0)
break;
- if (sscanf(line, "%" SCNu32, &u) != 1) {
+ if (strtouint32(line, &u32)) {
printf("Invalid head switch time `%s'\n", line);
continue;
}
- lp->d_headswitch = u;
+ lp->d_headswitch = u32;
break;
}
/* d_trkseek */
for (;;) {
@@ -386,15 +384,15 @@
i = getinput(":", "Track seek time (usec)", def, line);
if (i == -1)
return;
else if (i == 0)
break;
- if (sscanf(line, "%" SCNu32, &u) != 1) {
+ if (strtouint32(line, &u32)) {
printf("Invalid track seek time `%s'\n", line);
continue;
}
- lp->d_trkseek = u;
+ lp->d_trkseek = u32;
break;
}
}
@@ -413,32 +411,33 @@
(void) strncpy(lp->d_packname, line, sizeof(lp->d_packname));
}
static void
-cmd_round(struct disklabel *lp, char *s, int fd)
+cmd_align(struct disklabel *lp, char *s, int fd)
{
int i;
char line[BUFSIZ];
+ char *outputstr;
- i = getinput(":", "Rounding", rounding ? "cylinders" : "sectors", line);
+ if (!asprintf(&outputstr, "%d", ptn_alignment))
+ return;
+ i = getinput(":", "Rounding", outputstr, line);
+ free(outputstr);
if (i <= 0)
return;
- switch (line[0]) {
- case 'c':
- case 'C':
- rounding = 1;
- return;
- case 's':
- case 'S':
- rounding = 0;
- return;
- default:
- printf("Rounding can be (c)ylinders or (s)ectors\n");
- return;
- }
+ if (strlen(line) == 1)
+ if (line[0] == 'c' || line[0] == 'C') {
+ set_ptn_alignment(lp, "1cyl");
+ return;
+ } else if (line[0] == 's' || line[0] == 'S') {
+ set_ptn_alignment(lp, "1sec");
+ return;
+ }
+
+ set_ptn_alignment(lp, line);
}
static void
cmd_part(struct disklabel *lp, char *s, int fd)
@@ -502,12 +501,16 @@
} else {
p->p_offset = cp[line[0] - 'a'].p_offset +
cp[line[0] - 'a'].p_size;
}
} else {
- if ((im = getnum(lp, line, 0)) == -1 || im < 0) {
+ if (strlen(line) == 1 && line[0] == '$')
+ im = 0;
+ else if ((im = modstrtoint(lp, line, 1)) == -1) {
printf("Bad offset `%s'\n", line);
+ printf("Valid units: (S)ectors, (C)ylinders,
(K)ilo, (M)ega, "
+ "(G)iga, (T)era\n");
continue;
} else if (im > 0xffffffffLL ||
(uint32_t)im > lp->d_secperunit) {
printf("Offset `%s' out of range\n", line);
continue;
@@ -522,13 +525,16 @@
def, line);
if (i == -1)
return;
else if (i == 0)
break;
- if ((im = getnum(lp, line, lp->d_secperunit - p->p_offset))
- == -1) {
+ if (strlen(line) == 1 && line[0] == '$')
+ im = lp->d_secperunit - p->p_offset;
+ else if ((im = modstrtoint(lp, line, 1)) == -1) {
printf("Bad size `%s'\n", line);
+ printf("Valid units: (S)ectors, (C)ylinders, (K)ilo,
(M)ega, "
+ "(G)iga, (T)era\n");
continue;
} else if (im > 0xffffffffLL ||
(im + p->p_offset) > lp->d_secperunit) {
printf("Size `%s' out of range\n", line);
continue;
@@ -702,76 +708,13 @@
static void
defnum(struct disklabel *lp, char *buf, uint32_t size)
{
- (void) snprintf(buf, BUFSIZ, "%.40gc, %" PRIu32 "s, %.40gM",
+ (void) snprintf(buf, BUFSIZ, "%.4gc, %" PRIu32 "s, %.4gM",
size / (float) lp->d_secpercyl,
size, size * (lp->d_secsize / (float) (1024 * 1024)));
-}
-
-
-static intmax_t
-getnum(struct disklabel *lp, char *buf, intmax_t defaultval)
-{
- char *ep;
- double d;
- intmax_t rv;
-
- if (defaultval && buf[0] == '$' && buf[1] == 0)
- return defaultval;
-
- d = strtod(buf, &ep);
- if (buf == ep)
- return -1;
-
-#define ROUND(a) ((((a) / lp->d_secpercyl) + \
- (((a) % lp->d_secpercyl) ? 1 : 0)) * lp->d_secpercyl)
-
- switch (*ep) {
- case '\0':
- case 's':
- case 'S':
- rv = (intmax_t) d;
- break;
-
- case 'c':
- case 'C':
- rv = (intmax_t) (d * lp->d_secpercyl);
- break;
-
- case 'k':
- case 'K':
- rv = (intmax_t) (d * 1024 / lp->d_secsize);
- break;
-
- case 'm':
- case 'M':
- rv = (intmax_t) (d * 1024 * 1024 / lp->d_secsize);
- break;
-
- case 'g':
- case 'G':
- rv = (intmax_t) (d * 1024 * 1024 * 1024 / lp->d_secsize);
- break;
-
- case 't':
- case 'T':
- rv = (intmax_t) (d * 1024 * 1024 * 1024 * 1024 /
lp->d_secsize);
- break;
-
- default:
- printf("Unit error %c\n", *ep);
- printf("Valid units: (S)ectors, (C)ylinders, (K)ilo, (M)ega, "
- "(G)iga, (T)era");
- return -1;
- }
-
- if (rounding)
- return ROUND(rv);
- else
- return rv;
}
void
interact(struct disklabel *lp, int fd)
--- sbin/disklabel/main.c
+++ sbin/disklabel/main.c
@@ -108,10 +108,12 @@
#else
#include <sys/ioctl.h>
#include <sys/disklabel.h>
#include <sys/disklabel_acorn.h>
#include <sys/bootblock.h>
+#include <sys/sysctl.h>
+#include <sys/param.h>
#include <util.h>
#include <disktab.h>
#endif /* HAVE_NBTOOL_CONFIG_H */
#include "pathnames.h"
@@ -155,10 +157,11 @@
static int Iflag; /* Read/write direct, but default if absent */
static int lflag; /* List all known file system types and exit */
static int mflag; /* Expect disk to contain an MBR */
static int verbose;
static int read_all; /* set if op = READ && Aflag */
+int ptn_alignment = 1; /* Partition alignment. extern in extern.h */
static int write_label(int);
static int readlabel_direct(int);
static void writelabel_direct(int);
static int update_label(int, u_int, u_int);
@@ -265,15 +268,18 @@
main(int argc, char *argv[])
{
FILE *t;
int ch, f, error;
char *dkname;
+ char *partstr = NULL;
+ char *labelstr = NULL;
+ char *alignstr = NULL;
struct stat sb;
int writable;
enum {
UNSPEC, EDIT, READ, RESTORE, SETWRITABLE, SETREADONLY,
- WRITE, INTERACT, DELETE
+ WRITE, INTERACT, DELETE, BATCH
} op = UNSPEC, old_op;
mflag = GETLABELUSESMBR();
if (mflag < 0) {
warn("getlabelusesmbr() failed");
@@ -283,11 +289,11 @@
/* We must avoid doing any ioctl requests */
Fflag = rflag = 1;
#endif
error = 0;
- while ((ch = getopt(argc, argv, "ACDFINRWb:ef:ilmrs:tvw")) != -1) {
+ while ((ch = getopt(argc, argv, "ACDFINRWa:ef:s:p:uilmrtvw")) != -1) {
old_op = op;
switch (ch) {
case 'A': /* Action all labels */
Aflag = 1;
rflag = 1;
@@ -314,10 +320,15 @@
op = SETREADONLY;
break;
case 'W': /* Allow writes to label sector */
op = SETWRITABLE;
break;
+ case 'a': /* Set partition alignment */
+ alignstr = strdup(optarg);
+ if (!alignstr)
+ err(1, "Could not allocate string.");
+ break;
case 'e': /* Edit label with $EDITOR */
op = EDIT;
break;
case 'f': /* Name of disktab file */
if (setdisktab(optarg) == -1)
@@ -330,10 +341,15 @@
lflag = 1;
break;
case 'm': /* Expect disk to have an MBR */
mflag ^= 1;
break;
+ case 'p': /* Change disklabel values */
+ labelstr = strdup(optarg);
+ if (!labelstr)
+ err(1, "Could not allocate string.");
+ break;
case 'r': /* Read/write label directly from disk */
rflag = 1;
break;
case 't': /* Format output as a disktab entry */
tflag = 1;
@@ -341,10 +357,18 @@
case 'v': /* verbose/diag output */
verbose++;
break;
case 'w': /* Write label based on disktab entry */
op = WRITE;
+ break;
+ case 's': /* Preset partition values. */
+ partstr = strdup(optarg);
+ if (!partstr)
+ err(1, "Could not allocate string.");
+ break;
+ case 'u': /* Update label without further interaction. */
+ op = BATCH;
break;
case '?':
default:
usage();
}
@@ -381,22 +405,41 @@
if (argc != 1)
usage();
Dflag = 2;
writelabel_direct(f);
break;
+
+ case BATCH:
+ if (argc != 1)
+ usage();
+ readlabel(f);
+ set_ptn_alignment(&lab, alignstr);
+ free(alignstr);
+ parse_partstr(&lab, &partstr);
+ parse_labelstr(&lab, &labelstr);
+ batchedit(&lab, f);
+ break;
case EDIT:
if (argc != 1)
usage();
readlabel(f);
+ set_ptn_alignment(&lab, alignstr);
+ free(alignstr);
+ parse_partstr(&lab, &partstr);
+ parse_labelstr(&lab, &labelstr);
error = edit(f);
break;
case INTERACT:
if (argc != 1)
usage();
readlabel(f);
+ set_ptn_alignment(&lab, alignstr);
+ free(alignstr);
+ parse_partstr(&lab, &partstr);
+ parse_labelstr(&lab, &labelstr);
/*
* XXX: Fill some default values so checklabel does not fail
*/
if (lab.d_bbsize == 0)
lab.d_bbsize = BBSIZE;
@@ -414,10 +457,14 @@
/* Label got printed in the bowels of readlabel */
break;
if (tflag)
makedisktab(stdout, &lab);
else {
+ set_ptn_alignment(&lab, alignstr);
+ free(alignstr);
+ parse_partstr(&lab, &partstr);
+ parse_labelstr(&lab, &labelstr);
showinfo(stdout, &lab, specname);
showpartitions(stdout, &lab, Cflag);
}
error = checklabel(&lab);
if (error)
@@ -1906,6 +1953,128 @@
free(list);
}
}
return ret;
+}
+
+/* Convert a string to a uint16_t. Returns -1 on error, 0 on success. */
+int
+strtouint16(char *intstr, uint16_t *val16)
+{
+ long int lval;
+ char *endstr;
+
+ lval = strtoll(intstr, &endstr, 10);
+ if (*endstr != '\0')
+ return -1;
+ if (lval > UINT16_MAX)
+ return -1;
+
+ *val16 = (uint16_t) lval;
+
+ return 0;
+}
+
+/* Convert a string to a uint32_t. Returns -1 on error, 0 on success. */
+int
+strtouint32(char *intstr, uint32_t *val32)
+{
+ long int lval;
+ char *endstr;
+
+ lval = strtoll(intstr, &endstr, 10);
+ if (*endstr != '\0')
+ return -1;
+ if (lval > UINT32_MAX)
+ return -1;
+
+ *val32 = (uint32_t) lval;
+
+ return 0;
+}
+
+/* Convert a string with modifier to int, return negative value on error.
+ * If rounding is 0, do not round. If rounding is 1, round. If rounding is 2,
+ * round down, if rounding is 3, round up. */
+intmax_t
+modstrtoint(struct disklabel *lp, char *modstr, int rounding)
+{
+ char *cp;
+ intmax_t ret;
+ int len, part;
+ size_t partlen;
+
+ ret = strtoll(modstr, &cp, 10);
+ len = strcspn(cp, " \t\n");
+ if (modstr == cp)
+ return -1;
+ if (!strncasecmp(cp, "sector", len))
+ {}
+ else if (!strncasecmp(cp, "tb", len)) /* Might be too long for int. */
+ ret *= (intmax_t)(1024 * 1024 * 1024 / lp->d_secsize * 1024);
+ else if (!strncasecmp(cp, "gb", len))
+ ret *= 1024 * 1024 * 1024 / lp->d_secsize;
+ else if (!strncasecmp(cp, "mb", len))
+ ret *= 1024 * 1024 / lp->d_secsize;
+ else if (!strncasecmp(cp, "kb", len))
+ ret *= 1024 / lp->d_secsize;
+ else if (!strncasecmp(cp, "cylinder", len))
+ ret *= lp->d_secpercyl;
+ else if (!strncasecmp(cp, "%", len)) {
+ if (ret < 0 || ret > 100)
+ err(1, "Percentage must be in [0, 100], is %d.", ret);
+ /* lp->d_secperunit is the best approximation for the right
value we can
+ * get. We cannot determine the mbr partition size for sure if
there is
+ * one, so simply compute percentages of the whole disk. */
+ // XXX: We could also use some magic involving checks of
partition c,
+ // etc., to be sure to take percentages of the mbr.
+ ret *= lp->d_secperunit / 100;
+ ret += ptn_alignment;
+ } else
+ return -1;
+
+ switch (rounding) {
+ case 0: /* Nothing at all. */
+ break;
+ case 1: /* Round. */
+ ret = ((ret / ptn_alignment) + (ret % ptn_alignment ? 1
: 0)) * ptn_alignment;
+ break;
+ case 2: /* Round down. */
+ ret = (ret / ptn_alignment) * ptn_alignment;
+ break;
+ }
+
+ return ret;
+}
+
+/* The alignment stuff is mostly copied from fdisk(8). */
+void
+set_ptn_alignment(struct disklabel *lp, char *alignstr)
+{
+ intmax_t i;
+
+ /* Default to using 'traditional' cylinder alignment */
+ ptn_alignment = lp->d_secpercyl;
+
+ if (alignstr != NULL) {
+ i = modstrtoint(lp, alignstr, 0);
+ if (i != -1)
+ ptn_alignment = (unsigned int)i;
+ else
+ errx(1, "Invalid alignment specifier.");
+ } else {
+ i = lp->d_partitions[0].p_offset + lp->d_partitions[0].p_size;
+ if (i != 0) {
+ if (!(i & 2047)) {
+ /* Should nearly always extend to 1MB */
+ ptn_alignment = 2048;
+ }
+ } else {
+ /* Use 1MB alignment for large disks */
+ if (lp->d_secperunit > 2048 * 1024 * 128)
+ ptn_alignment = 2048;
+ }
+ }
+
+ return;
}
--- sbin/disklabel/extern.h +++ sbin/disklabel/extern.h @@ -28,9 +28,17 @@ int checklabel(struct disklabel *); void showinfo(FILE *, struct disklabel *, const char *); void showpartitions(FILE *, struct disklabel *, int); void showpartition(FILE *, struct disklabel *, int, int); void interact(struct disklabel *, int); +void parse_partstr(struct disklabel *, char **); +void parse_labelstr(struct disklabel *, char **); +void batchedit(struct disklabel *, int); +void set_ptn_alignment(struct disklabel *, char *); +int strtouint16(char *, uint16_t *); +int strtouint32(char *, uint32_t *); +intmax_t modstrtoint(struct disklabel *, char *, int); int list_fs_types(void); extern char specname[]; extern int Cflag; +extern int ptn_alignment;
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: interact.c,v 1.35 2011/01/06 21:39:01 apb Exp $");
#endif /* lint */
#include <sys/param.h>
#define FSTYPENAMES
#define DKTYPENAMES
#include <err.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#if HAVE_NBTOOL_CONFIG_H
#define getmaxpartitions() MAXPARTITIONS
#include <nbinclude/sys/disklabel.h>
#else
#include <util.h>
#include <sys/disklabel.h>
#endif /* HAVE_NBTOOL_CONFIG_H */
#include "extern.h"
static void change_type(struct disklabel *, char *);
static void change_typename(struct disklabel *, char *);
static void change_packname(struct disklabel *, char *);
static void change_npartitions(struct disklabel *, char *);
static void change_secsize(struct disklabel *, char *);
static void change_nsectors(struct disklabel *, char *);
static void change_ntracks(struct disklabel *, char *);
static void change_secpercyl(struct disklabel *, char *);
static void change_ncylinders(struct disklabel *, char *);
static void change_secperunit(struct disklabel *, char *);
static void change_rpm(struct disklabel *, char *);
static void change_interleave(struct disklabel *, char *);
static void change_trackskew(struct disklabel *, char *);
static void change_cylskew(struct disklabel *, char *);
static void change_headswitch(struct disklabel *, char *);
static void change_trseek (struct disklabel *, char *);
static struct changefunc {
const char *name;
void (*func)(struct disklabel *, char *);
} changefuncs[] = {
{ "type", change_type },
{ "typename", change_typename },
{ "packname", change_packname },
{ "npartitions", change_npartitions },
{ "secsize", change_secsize },
{ "nsectors", change_nsectors },
{ "ntracks", change_ntracks },
{ "secpercyl", change_secpercyl },
{ "ncylinders", change_ncylinders },
{ "secperunit", change_secperunit },
{ "rpm", change_rpm },
{ "interleave", change_interleave },
{ "trackskew", change_trackskew },
{ "cylskew", change_cylskew },
{ "headswitch", change_headswitch },
{ "trkseek", change_trseek },
{ NULL, NULL }
};
void
parse_partstr(struct disklabel *labelp, char **partstr)
{
int i, done;
intmax_t im;
int part;
char *parttok;
char *tokparam; /* Intermediate values for strtok_r */
struct partition *p, ps;
if (*partstr == NULL)
return;
/* Partition number */
parttok = strtok_r(*partstr, "/", &tokparam);
if (parttok == NULL)
errx(1, "Invalid partition string: Number not given");
if (strlen(parttok) != 1)
errx(1, "Invalid partition identifier %s", parttok);
part = parttok[0] - 'a';
p = &labelp->d_partitions[part];
if (part >= labelp->d_npartitions)
labelp->d_npartitions = part + 1;
(void)memcpy(&ps, p, sizeof(ps));
/* Partition start/offset */
// XXX: TODO: How to determine the offset, and e.g. alignment? Just
setting
// it to 0 is not enough, that wil make partitions really start at 0,
even
// if they are in an mbr.
parttok = strtok_r(NULL, "/", &tokparam);
if (parttok == NULL)
errx(1, "Invalid partition string: Offset/start not given");
if (strlen(parttok) == 1 &&
parttok[0] >= 'a' && parttok[0] < 'a' + getmaxpartitions()) {
struct partition *cp = labelp->d_partitions;
if ((cp[parttok[0] - 'a'].p_offset +
cp[parttok[0] - 'a'].p_size) >= labelp->d_secperunit)
errx(1, "Bad offset `%s'", parttok);
else
p->p_offset = cp[parttok[0] - 'a'].p_offset +
cp[parttok[0] - 'a'].p_size;
} else {
im = modstrtoint(labelp, parttok, 1);
if (im == -1)
errx(1, "Bad offset `%s'", parttok);
else if (im > 0xffffffffLL ||
(uint32_t)im > labelp->d_secperunit)
errx(1, "Offset `%s' out of range", parttok);
p->p_offset = (uint32_t)im;
}
/* Partition size */
parttok = strtok_r(NULL, "/", &tokparam);
if (parttok == NULL)
errx(1, "Invalid partition string: Size not given");
if ((im = modstrtoint(labelp, parttok, 2)) == -1)
errx(1, "Bad size `%s'", parttok);
else if (im > 0xffffffffLL ||
(im + p->p_offset) > labelp->d_secperunit)
errx(1, "Size `%s' out of range", parttok);
p->p_size = im;
/* Partition type */
parttok = strtok_r(NULL, "/", &tokparam);
if (parttok == NULL)
errx(1, "Invalid partition string: Type not given");
done = 0;
for (i = 0; i < FSMAXTYPES; i++)
if (!strcasecmp(parttok, fstypenames[i])) {
p->p_fstype = i;
done = 1;
}
if (!done)
errx(1, "Invalid partition type: %s", parttok);
/* Clear out partitions that are in our way */
done = 0;
for (i = 0; i < labelp->d_npartitions; i++)
if (((labelp->d_partitions[i].p_offset > p->p_offset &&
labelp->d_partitions[i].p_offset
< p->p_offset + p->p_size)
|| (labelp->d_partitions[i].p_offset
+ labelp->d_partitions[i].p_size
> p->p_offset
&& labelp->d_partitions[i].p_offset
+ labelp->d_partitions[i].p_size
< p->p_offset + p->p_size)
|| (labelp->d_partitions[i].p_offset < p->p_offset
&& labelp->d_partitions[i].p_offset
+ labelp->d_partitions[i].p_size
> p->p_offset + p->p_size))
&& labelp->d_partitions[i].p_fstype != FS_UNUSED) {
labelp->d_partitions[i].p_offset = 0;
labelp->d_partitions[i].p_size = 0;
if (labelp->d_npartitions == i - 1)
done = 1;
}
/* Decrease npartitions appropriately */
if (done) {
for (i = 0; i < labelp->d_npartitions; i++) {
if (labelp->d_partitions[i].p_size == 0
&& labelp->d_partitions[i].p_offset ==
0)
im = i;
}
labelp->d_npartitions = (uint16_t)im + 1;
}
free(*partstr);
return;
}
void
parse_labelstr(struct disklabel *labelp, char **labelstr)
{
int funcdone;
char *labeltok;
char *paramtok, *valuetok;
char *tokparam, *tokparam2; /* Intermediate values for strtok_r */
struct changefunc *tmpcfunc;
if (*labelstr == NULL)
return;
for (labeltok = strtok_r(*labelstr, ",", &tokparam); labeltok != NULL;
labeltok = strtok_r(NULL, ",", &tokparam)) {
funcdone = 0;
paramtok = strtok_r(labeltok, "=", &tokparam2);
if (paramtok == NULL)
errx(1, "Invalid parameter to -p");
valuetok = strtok_r(labeltok, "=", &tokparam2);
if (valuetok == NULL)
errx(1, "Invalid parameter to -p: %s has no value",
paramtok);
if (strtok_r(labeltok, "=", &tokparam2) != NULL)
errx(1, "Too many equality signs for flag -p: %s",
paramtok);
for (tmpcfunc = changefuncs; tmpcfunc->name != NULL;
*tmpcfunc++) {
if (!strcmp(tmpcfunc->name, paramtok)) {
funcdone = 1;
(*tmpcfunc->func)(labelp, valuetok);
break;
}
}
if (funcdone == 0)
errx(1, "Invalid parameter to -p: %s", paramtok);
}
return;
}
void
batchedit(struct disklabel *labelp, int fd)
{
if (checklabel(labelp) != 0) {
errx(1, "Internal failure: Invalid label");
}
if (writelabel(fd, labelp) != 0) {
errx(1, "Label not written");
}
printf("Label written\n");
return;
}
static void
change_type(struct disklabel *labelp, char *labelstr)
{
uint16_t i;
i = labelp->d_type;
if (i < 0 || i >= DKMAXTYPES)
i = 0;
for (i = 0; i < DKMAXTYPES; i++)
if (!strcasecmp(dktypenames[i], labelstr)) {
labelp->d_type = i;
return;
}
if (strtouint16(labelstr, &i) || i >= DKMAXTYPES) {
errx(1, "Unknown disk type: %s", labelstr);
}
labelp->d_type = i;
}
static void
change_typename(struct disklabel *labelp, char *labelstr)
{
if (strlen(labelstr) > sizeof(labelp->d_typename))
warn("Label typename %s too long, max. length: %d", labelstr,
sizeof(labelp->d_typename));
(void) strncpy(labelp->d_typename, labelstr,
sizeof(labelp->d_typename));
}
static void
change_packname(struct disklabel *labelp, char *labelstr)
{
if (strlen(labelstr) > sizeof(labelp->d_packname))
warn("Label packname %s too long, max. length: %d", labelstr,
sizeof(labelp->d_packname));
(void) strncpy(labelp->d_packname, labelstr,
sizeof(labelp->d_packname));
}
static void
change_npartitions(struct disklabel *labelp, char *labelstr)
{
uint16_t i;
if (strtouint16(labelstr, &i))
errx(1, "Invalid npartitions: %s", labelstr);
labelp->d_npartitions = i;
}
static void
change_secsize(struct disklabel *labelp, char *labelstr)
{
uint32_t i;
if (strtouint32(labelstr, &i))
errx(1, "Invalid secsize: %s", labelstr);
labelp->d_secsize = i;
}
static void
change_nsectors(struct disklabel *labelp, char *labelstr)
{
uint32_t i;
if (strtouint32(labelstr, &i))
errx(1, "Invalid nsectors: %s", labelstr);
labelp->d_secsize = i;
}
static void
change_ntracks(struct disklabel *labelp, char *labelstr)
{
uint32_t i;
if (strtouint32(labelstr, &i))
errx(1, "Invalid ntracks: %s", labelstr);
labelp->d_ntracks = i;
}
static void
change_secpercyl(struct disklabel *labelp, char *labelstr)
{
uint32_t i;
if (strtouint32(labelstr, &i))
errx(1, "Invalid secpercyl: %s", labelstr);
labelp->d_secpercyl = i;
}
static void
change_ncylinders(struct disklabel *labelp, char *labelstr)
{
uint32_t i;
if (strtouint32(labelstr, &i))
errx(1, "Invalid ncylinders: %s", labelstr);
labelp->d_ncylinders = i;
}
static void
change_secperunit(struct disklabel *labelp, char *labelstr)
{
uint32_t i;
if (strtouint32(labelstr, &i))
errx(1, "Invalid secperunit: %s", labelstr);
labelp->d_secperunit = i;
}
static void
change_rpm(struct disklabel *labelp, char *labelstr)
{
// XXX: What is up with rpm? Why wasn't it set from disklabel -i before?
}
static void
change_interleave(struct disklabel *labelp, char *labelstr)
{
uint16_t i;
if (strtouint16(labelstr, &i))
errx(1, "Invalid interleave: %s", labelstr);
labelp->d_interleave = i;
}
static void
change_trackskew(struct disklabel *labelp, char *labelstr)
{
uint16_t i;
if (strtouint16(labelstr, &i))
errx(1, "Invalid trackskew: %s", labelstr);
labelp->d_trackskew = i;
}
static void
change_cylskew(struct disklabel *labelp, char *labelstr)
{
uint16_t i;
if (strtouint16(labelstr, &i))
errx(1, "Invalid cylskew: %s", labelstr);
labelp->d_cylskew = i;
}
static void
change_headswitch(struct disklabel *labelp, char *labelstr)
{
uint16_t i;
if (strtouint16(labelstr, &i))
errx(1, "Invalid headswitch: %s", labelstr);
labelp->d_headswitch = i;
}
static void
change_trseek(struct disklabel *labelp, char *labelstr)
{
uint32_t i;
if (strtouint32(labelstr, &i))
errx(1, "Invalid trkseek: %s", labelstr);
labelp->d_trkseek = i;
}
Attachment:
signature.asc
Description: PGP signature