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